【问题标题】:Python Tkinter Save Listbox Item Ordering to Sqlite DatabasePython Tkinter 将列表框项排序保存到 Sqlite 数据库
【发布时间】:2016-08-30 22:36:41
【问题描述】:

我有一个拖放列表框 (found here),允许用户向上或向下拖动/移动项目以重新排序。

我有一个 db.sqlite 文件,最初看起来像这样:

>>> make_df()
    ordering          fruit
0          0         apples
1          1        oranges
2          2    blueberries
3          3     watermelon
4          4     cantaloupe
5          5          pears
6          6    pomegranate
7          7    raspberries
8          8   blackberries
9          9  boysenberries
10        10     nectarines

我要做的是重新排列列表框中的项目并将该顺序保存到数据库中,这样当我重新启动程序时,项目的顺序与我上次使用它时的顺序相同。

问题: 每次我重新启动程序时,列表框中的项目总是以相同的顺序排列。但是,当我重新排序项目,然后运行 ​​make_df 时,它会查看数据库以查看排序并返回一个数据框,它显示该会话期间数据库确实更新了。 只是没有永久保存它,这是我想不通的。

import tkinter as tk
import pandas as pd
import sqlite3
root = tk.Tk()

def make_sqlite_db_for_stackoverflow():
  connection = sqlite3.connect('db.sqlite')
  db_file_name = 'db.sqlite'
  df = pd.DataFrame(
    [(0, 'apples'), (1, 'oranges'), (2, 'blueberries'), (3, 'watermelon'),
     (4, 'cantaloupe'), (5, 'pears'), (6, 'pomegranate'), (7, 'raspberries'),
     (8, 'blackberries'), (9, 'boysenberries'), (10, 'nectarines')],
    columns=['ordering', 'fruit']
    )
  df.to_sql('columns', connection, index=False, if_exists='replace')
  connection.close()

make_sqlite_db_for_stackoverflow()

def make_df():
  print(pd.DataFrame(sqlite3.connect('db.sqlite').cursor().execute(
    'SELECT * FROM columns ORDER BY "ordering";').fetchall(), columns=['ordering', 'fruit']))

class Drag_and_Drop_Listbox(tk.Listbox):
  """ A tk listbox with drag'n'drop reordering of entries. """
  def __init__(self, master, **kw):
    kw['selectmode'] = tk.EXTENDED
    tk.Listbox.__init__(self, master, kw)
    self.bind('<Button-1>', self.setCurrent)
    self.bind('<B1-Motion>', self.shiftSelection)
    self.curIndex = None
  def setCurrent(self, event):
    self.curIndex = self.nearest(event.y)
  def shiftSelection(self, event):
    i = self.nearest(event.y)
    if i < self.curIndex:
      x = self.get(i)
      self.delete(i)
      self.insert(i+1, x)
      self.curIndex = i
    elif i > self.curIndex:
      x = self.get(i)
      self.delete(i)
      self.insert(i-1, x)
      self.curIndex = i

def update_ordering(*args):
  connect = sqlite3.connect('db.sqlite')
  cursor = connect.cursor()
  field_ordering = [(order,fruit) for order,fruit in enumerate(ddlistbox.get(0, 'end'))]
  print(field_ordering)
  for field in field_ordering:
    cursor.execute("UPDATE columns SET 'ordering'="+str(field[0])+" WHERE fruit='"+field[1]+"';")
  connect.commit()
  connect.close()
  print(ddlistbox.curselection())

scrollbar = tk.Scrollbar(root, orient="vertical")
ddlistbox = Drag_and_Drop_Listbox(root, yscrollcommand=scrollbar.set)
scrollbar.grid(row=0, column=1, sticky='ns')
scrollbar.config(command=ddlistbox.yview)

def get_sqlite_report_fields():
  conn = sqlite3.connect('db.sqlite')
  conn.row_factory = lambda cursor, row: row[0]
  cursor = conn.cursor()
  fetch = cursor.execute("SELECT fruit FROM columns ORDER BY 'ordering';").fetchall()
  conn.close()
  return fetch

for fruit in get_sqlite_report_fields():
  ddlistbox.insert(0, fruit)
ddlistbox.config(width=30)
ddlistbox.bind('<Double-Button-1>' , func=update_ordering)
ddlistbox.grid(row=0, column=0)

button = tk.Button(root, text='Check', command=update_ordering)
button.grid(row=1, column=0)

root.mainloop()

【问题讨论】:

  • 您的代码有效吗?它会引发异常吗?
  • 您的数据库事务中是否缺少commit
  • 我只在update_ordering 函数中更新排序时使用commit。所有其他时间,我都是来自数据库的SELECTing,而不是更新。
  • 这个脚本总是在开头运行make_sqlite_db_for_stackoverflow()。所以它总是将数据库重新初始化为默认值。您可能想要检查数据库,并且仅在它不存在时才进行初始化。
  • 我知道。它旨在帮助人们重新创建创建数据库的场景。第一次运行后可以注释掉,但问题仍然存在。这不是问题。

标签: python tkinter sqlite drag-and-drop listbox


【解决方案1】:

非常怀疑有人会回答我的问题,所以我发布了我的解决方案。它使用拖放列表框允许用户在列表框中排列项目并将他们的项目排序保存到数据库中以供下次使用。

import tkinter as tk
import pandas as pd
import sqlite3
root = tk.Tk()

class Drag_and_Drop_Listbox(tk.Listbox):
  """ A tk listbox with drag'n'drop reordering of entries. """
  def __init__(self, master, **kw):
    kw['selectmode'] = tk.EXTENDED
    tk.Listbox.__init__(self, master, kw)
    self.bind('<Button-1>', self.setCurrent)
    self.bind('<B1-Motion>', self.shiftSelection)
    self.curIndex = None
  def setCurrent(self, event):
    self.curIndex = self.nearest(event.y)
  def shiftSelection(self, event):
    i = self.nearest(event.y)
    if i < self.curIndex:
      x = self.get(i)
      self.delete(i)
      self.insert(i+1, x)
      self.curIndex = i
    elif i > self.curIndex:
      x = self.get(i)
      self.delete(i)
      self.insert(i-1, x)
      self.curIndex = i

def update_ordering(*args):
  connect = sqlite3.connect('db.sqlite')
  cursor = connect.cursor()
  field_ordering = [(order,fruit) for order,fruit in enumerate(ddlistbox.get(0, 'end'))]
  print(field_ordering)
  for field in field_ordering:
    cursor.execute("UPDATE columns SET 'ordering'="+str(field[0])+" WHERE fruit='"+field[1]+"';")
  connect.commit()
  connect.close()
  print(ddlistbox.curselection())

scrollbar = tk.Scrollbar(root, orient="vertical")
ddlistbox = Drag_and_Drop_Listbox(root, yscrollcommand=scrollbar.set, activestyle='none')
scrollbar.grid(row=0, column=1, sticky='ns')
scrollbar.config(command=ddlistbox.yview)

conn = sqlite3.connect('db.sqlite')
conn.row_factory = lambda cursor, row: row[0]
cursor = conn.cursor()
fetch = cursor.execute("SELECT fruit FROM columns ORDER BY ordering ASC").fetchall()
for field in fetch:
  ddlistbox.insert(tk.END, field)
ddlistbox.config(width=30)
ddlistbox.grid(row=0, column=0)

button = tk.Button(root, text='Check', command=update_ordering)
button.grid(row=1, column=0)

root.mainloop()

【讨论】:

    猜你喜欢
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多