更新数据库时如何更新 mainwindow 中的小部件

How to update widgets in mainwindow when database is updated

提问人:Skepta 提问时间:11/16/2023 更新时间:11/16/2023 访问量:14

问:

我有一个应用程序,可以通过添加、删除或更新其条目来与其数据库进行交互。我要做的是,每当有新条目或对数据库执行操作时,我想发出一个一般信号,告诉主窗口重新绘制 ClipBoardWidget 小部件,因为现在可能会有更多、更少,或者小部件可能会更新新信息...... 截至目前,这仅适用于您在应用程序中执行操作并且您必须关闭它并重新打开应用程序才能更改它时,它不是动态的......

下面是 MainWindow 类:

from PySide6.QtWidgets import (QMainWindow,
                               QToolBar,
                               QWidget,
                               QToolButton,
                               QVBoxLayout,
                               QScrollArea
                               )
from PySide6.QtGui import (QAction, QIcon)
from PySide6.QtCore import (Qt, QCoreApplication, QSize, Slot)
from controller.database import Database
from gui.add import AddClipboard
from gui.search import SearchClipboard
from gui.remove import RemoveClipboard
from gui.clipboardwidget import ClipBoardWidget

class GUI(QMainWindow):
    def __init__(self) -> None:
        super().__init__()
 
        self.setWindowTitle("Clipboard Manager")

        self.tool_bar = QToolBar(self)
        self.tool_bar.setObjectName(u"toolBar")
        self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
        self.tool_bar.setMovable(False)

        self.add_cb_btn = QToolButton()
        self.add_cb_btn.setIcon(QIcon("gui/assets/add.svg"))
        self.add_cb_btn.clicked.connect(self.addcbshow)

        self.remove_cb_btn = QToolButton()
        self.remove_cb_btn.setIcon(QIcon("gui/assets/trash.svg"))
        self.remove_cb_btn.clicked.connect(self.removecbshow)


        self.search_cb_btn = QToolButton()
        self.search_cb_btn.setIcon(QIcon("gui/assets/search.svg"))
        self.search_cb_btn.clicked.connect(self.searchcbshow)

        self.tool_bar.addWidget(self.add_cb_btn)
        self.tool_bar.addWidget(self.remove_cb_btn)
        self.tool_bar.addWidget(self.search_cb_btn)


        self.slate_layout = QVBoxLayout()
        self.scroll_cb = QScrollArea()
        self.slate = QWidget()
        self.db = Database()

        for u in self.db.GetClipboards():
            obj = ClipBoardWidget(u[0], u[2], u[1], u[3])
            self.slate_layout.addWidget(obj)
        
        self.slate_layout.setStretch(0,0)
        
        self.slate.setLayout(self.slate_layout)

        self.scroll_cb.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scroll_cb.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scroll_cb.setWidgetResizable(True)
        self.scroll_cb.setWidget(self.slate)
    
        self.setCentralWidget(self.scroll_cb)

    @Slot()
    def addcbshow(self):
        global g1
        g1 = AddClipboard()
        g1.show()

    
    @Slot()
    def removecbshow(self):
        global g2
        g2 = RemoveClipboard()
        g2.show()
    
    @Slot()
    def searchcbshow(self):
        global g3
        g3 = SearchClipboard()
        g3.show()

ClipBoardWidget 类:

class ClipBoardWidget(QWidget):
    def __init__(self, title, date, categories, data) -> None:
        super().__init__()

        self.title = title
        self.db = Database()
        self.data = data

        self.cbwidget_layout = QHBoxLayout()
        self.title_label = QLabel(title)
        self.date_label = QLabel(date)
        self.categories_label = QLabel(categories)
        self.data_label = QLabel(self.data)
        self.edit_button = QPushButton(QIcon("gui/assets/edit.svg"), "")
        self.edit_button.clicked.connect(self.edit_cb)
        self.remove_button = QPushButton(QIcon("gui/assets/trash.svg"), "")
        self.remove_button.clicked.connect(self.remove_cb)
        self.copy_to_cb_button = QPushButton(QIcon("gui/assets/copy.svg"), "")
        self.copy_to_cb_button.clicked.connect(self.copy_cb)

        self.cbwidget_layout.addWidget(self.title_label)
        self.cbwidget_layout.addWidget(self.date_label)
        self.cbwidget_layout.addWidget(self.categories_label)
        self.cbwidget_layout.addWidget(self.data_label)
        self.cbwidget_layout.addWidget(self.edit_button)
        self.cbwidget_layout.addWidget(self.remove_button)
        self.cbwidget_layout.addWidget(self.copy_to_cb_button)
        
        self.setLayout(self.cbwidget_layout)
    
    @Slot()
    def edit_cb(self):
        global g1
        g1 = EditClipboard()
        g1.show()
    @Slot()
    def remove_cb(self):
        self.db.RemoveClipboard(self.title)
    @Slot()
    def copy_cb(self):
        pyperclip.copy(self.data)

“添加、编辑、删除”和“搜索”对话框:

class SearchClipboard(QDialog):
    def __init__(self) -> None:
        super().__init__()

        self.setWindowTitle("Search Clipboard")

class RemoveClipboard(QDialog):
    def __init__(self) -> None:
        super().__init__()

        self.setWindowTitle("Remove Clipboard")
        self.db = Database()
        self.setWindowTitle("Add Clipboard")

        self.lay = QGridLayout()

        self.remove_by_name = QLabel("Remove clipboard by name")
        self.remove_by_name_lineedit = QLineEdit()

        self.remove_cb_button = QPushButton(QIcon("gui/assets/trash.svg"), "Remove")
        self.remove_cb_button.clicked.connect(self.remove_cb_from_db)

        self.lay.addWidget(self.remove_by_name, 0, 0)
        self.lay.addWidget(self.remove_by_name_lineedit, 0, 1)
        self.lay.addWidget(self.remove_cb_button, 1,0 ,1, 2)
        
        self.setLayout(self.lay)

    @Slot()
    def remove_cb_from_db(self):
        self.db.RemoveClipboard(self.remove_by_name_lineedit.text())
        self.deleteLater()

class EditClipboard(QDialog):
    def __init__(self) -> None:

        super().__init__()

        self.db = Database()
        self.setWindowTitle("Add Clipboard")

        self.lay = QGridLayout()

        self.cb_name = QLabel("Name")
        self.cb_name_lineedit = QLineEdit()

        self.cb_data = QLabel("Data")
        self.cb_data_lineedit = QLineEdit()

        self.cb_categories = QLabel("Categories")
        self.cb_categories_lineedit = QLineEdit()

        self.seperator_info = QLabel("<i>Seperate categoris with ';'</i>")

        self.add_btn = QPushButton(QIcon("gui/assets/add.svg"), "Add")
        self.add_btn.clicked.connect(self.add_cb_to_db)

        self.lay.addWidget(self.cb_name, 0, 0)
        self.lay.addWidget(self.cb_name_lineedit, 0, 1)
        self.lay.addWidget(self.cb_data, 1, 0)
        self.lay.addWidget(self.cb_data_lineedit, 1, 1)
        self.lay.addWidget(self.cb_categories, 2, 0)
        self.lay.addWidget(self.cb_categories_lineedit, 2, 1)
        self.lay.addWidget(self.seperator_info, 3, 0 )
        self.lay.addWidget(self.add_btn,4,0,1,2)

        self.setLayout(self.lay)

    @Slot()
    def add_cb_to_db(self):
        title = self.cb_name_lineedit.text()
        categories = self.cb_categories_lineedit.text()
        date = datetime.datetime.now()
        data = self.cb_data.text()
        self.db.AddClipboard(title, categories, date, data)
        self.deleteLater()

class AddClipboard(QDialog):
    def __init__(self) -> None:

        super().__init__()

        self.db = Database()
        self.setWindowTitle("Add Clipboard")

        self.lay = QGridLayout()

        self.cb_name = QLabel("Name")
        self.cb_name_lineedit = QLineEdit()

        self.cb_data = QLabel("Data")
        self.cb_data_lineedit = QLineEdit()

        self.cb_categories = QLabel("Categories")
        self.cb_categories_lineedit = QLineEdit()

        self.seperator_info = QLabel("<i>Seperate categoris with ';'</i>")

        self.add_btn = QPushButton(QIcon("gui/assets/add.svg"), "Add")
        self.add_btn.clicked.connect(self.add_cb_to_db)

        self.lay.addWidget(self.cb_name, 0, 0)
        self.lay.addWidget(self.cb_name_lineedit, 0, 1)
        self.lay.addWidget(self.cb_data, 1, 0)
        self.lay.addWidget(self.cb_data_lineedit, 1, 1)
        self.lay.addWidget(self.cb_categories, 2, 0)
        self.lay.addWidget(self.cb_categories_lineedit, 2, 1)
        self.lay.addWidget(self.seperator_info, 3, 0 )
        self.lay.addWidget(self.add_btn,4,0,1,2)

        self.setLayout(self.lay)

    @Slot()
    def add_cb_to_db(self):
        title = self.cb_name_lineedit.text()
        categories = self.cb_categories_lineedit.text()
        date = datetime.datetime.now()
        data = self.cb_data.text()
        self.db.AddClipboard(title, categories, date, data)
        self.deleteLater()

最后,这是数据库管理器:

class UpdateEnum(IntEnum):
    TITLE = 1
    CATEGORIES = 2
    DATA = 3 

class Database():
    def __init__(self) -> None:
        self.con = sqlite3.connect("clipboardmanager.db")
        self.cur = self.con.cursor()

        with open("controller/tags.txt", "r") as f:
            self.data = f.readlines()

    def CreateTables(self):
        self.cur.execute("CREATE TABLE clipboard(title, category, date, data)")
    
    def AddClipboard(self, title: str, category: str, date: datetime, data: str):

        self.cur.execute("""
            INSERT INTO clipboard VALUES(?,?,?,?)
            """, (title, category, date, data))
        
        self.con.commit()

    def RemoveClipboard(self, title: str):
        self.cur.execute("DELETE from clipboard where title = ?", (title,))
        self.con.commit()

    def GetClipboards(self):
        self.cur.execute("SELECT * FROM clipboard")
        return self.cur.fetchall()
    
    def EditClipoard(self, what_to_edit: UpdateEnum, edit: str, title: str):
        if what_to_edit == UpdateEnum.TITLE:
            self.cur.execute("UPDATE clipboard SET title = ? WHERE title = ?", (edit,title))
            self.con.commit()
        elif what_to_edit == UpdateEnum.DATA:
            self.cur.execute("UPDATE clipboard SET data = ? WHERE title = ?", (edit,title))
            self.con.commit()
        elif what_to_edit == UpdateEnum.CATEGORIES:
            self.cur.execute("UPDATE clipboard SET category = ? WHERE title = ?", (edit,title))
            self.con.commit()

    def Close(self):
        self.cur.close()
        self.con.close()

main.py config.json文件中“setup”为真或假

class CBManager():
    def __init__(self) -> None:
        pass

    def _is_setup(self) -> bool:
        self._file = open("config.json")
        self._data = json.load(self._file)

        return self._data["setup"]
    
    def _setup(self) -> None:
        self.db = Database()
        self.db.CreateTables()
        self.db.Close()

        with open("config.json", "r") as json_file:
            data = json.load(json_file)

        data["setup"] = True

        with open("config.json", "w") as json_file:
            json.dump(data, json_file, indent=4)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle('Fusion')

    if CBManager()._is_setup():
        gui = GUI()
        gui.setFixedWidth(600)
        gui.setFixedHeight(400)
        gui.show()
    else:
        CBManager()._setup()
        gui = GUI()
        gui.setFixedWidth(600)
        gui.setFixedHeight(400)
        gui.show()

    sys.exit(app.exec())

一般的要点是应用程序从数据库加载所有条目,在 mainWindow 滚动区域的 ClipboardWidgets 中显示这些条目。执行添加、编辑、删除操作时,剪贴板小组件不会更新,直到您关闭整个应用程序并重新打开它。 我该如何解决这个问题?

pyqt pyside pyside6 pyqt6

评论

1赞 musicamante 11/17/2023
Qt已经为QtSql模块提供了一个QSqlTableModel,与任何模型一样,它有信号来通知应用程序所做的任何更改。假设您仅要从应用程序访问数据库,则可以将 QDataWidgetMapper 与此类模型一起使用,然后数据库上的任何更新都将反映在连接的小部件上。
0赞 Skepta 11/20/2023
哇,谢谢你,我什至不知道它的存在

答: 暂无答案