如何根据 PyQt5 中的用户输入添加对象?
How can I add objects based on user input in PyQt5?
我正在使用 PyQt5 和 SQL 制作一个基本的联系人应用程序。打开应用程序后,我想在屏幕上显示所有联系人。所以我想为每个联系人向 UI 添加一些小部件,但我不知道在开始时会添加多少小部件(因为用户可能会通过添加或删除联系人来更改联系人数量)所以我不能手动添加它们。我用 for 循环尝试过,但由于对象的名称必须彼此不同,所以它没有用。
代码如下:
from PyQt5 import QtCore, QtGui, QtWidgets
import sqlite3
class Contact:
def __init__(self, id, first_name, last_name, phone_numbers, note = ""):
self.id = id
self.first_name = first_name
self.last_name = last_name
self.phone_numbers = phone_numbers
self.note = note
def getBoxInfo(self):
return f"{self.first_name}, {self.last_name}"
def getAllInfo(self):
if self.note != "":
return f"{self.first_name}, {self.last_name}, {self.phone_numbers}, {self.note}"
else:
return f"{self.first_name}, {self.last_name}, {self.phone_numbers}, "
#setting the connection to the database
connection = sqlite3.connect('contacts.db')
cursor = connection.cursor()
#getting 'user' and 'phone_number' datas from the database
cursor.execute("SELECT * FROM users")
connection.commit()
Users = cursor.fetchall()
cursor.execute("SELECT * FROM phone_numbers")
connection.commit()
PhoneNumbers = cursor.fetchall()
#Putting together the 'user' and 'phone_number' datas in the 'Contact' class subject and adding them to an array
Contacts = []
for i in range(len(Users)):
newContact = Contact(Users[i][0], Users[i][1], Users[i][2], list(), Users[i][3])
if newContact.note == None:
newContact.note = ""
for j in PhoneNumbers:
if j[1] == Users[i][0]:
newContact.phone_numbers.append(j[2])
Contacts.append(newContact)
#Creating the UI
class Ui_MainWindow(object):
def setupUi(self, MainWindow, Contacts):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1200, 675)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
#The part I tried to create widgets as many as 'users'
for i in range(len(Contacts)):
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(30, 30, 241, 81))
self.widget.setObjectName(f"widget{i}")
self.pushButton = QtWidgets.QPushButton(self.widget)
self.pushButton.setGeometry(QtCore.QRect(150, 20, 75, 23))
self.pushButton.setObjectName(f"pushButton{i}")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 816, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow, Contacts)
MainWindow.show()
sys.exit(app.exec_())
这个问题与对象名称无关,而是因为小部件不断添加到相同的 固定 坐标。结果是您有重叠的小部件,您只能查看最后添加的小部件。
虽然您可以使用增加的 y
位置,但这不会很好地工作:即使假设您要调整主 window 基于最后添加的小部件位置,出于多种原因,使用固定几何形状被认为是一种不好的做法;在这种特定情况下,您最终可能会得到一个太高的 window,如果您尝试调整它的大小,一些小部件将被隐藏。
解决方案是使用layout managers,确保所有内容都正确显示,并且window永远不会小于其子项所需的大小。
对于这种情况,QVBoxLayout 可能是一个不错的选择。
请注意,编辑 pyuic 生成的文件也被认为是一种不好的做法,因此我建议您在 Designer 中使用 empty main window 重新启动项目,保存UI,用 pyuic 生成文件 agan,然后在主脚本中导入该文件。在以下示例中,我假设您将该文件命名为 mainWindow_ui.py
:
from PyQt5 import QtWidgets
from mainWindow_ui import Ui_MainWindow
# ...
# contacts loading code...
# ...
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
layout = QtWidgets.QVBoxLayout(self.centralWidget())
self.contactWidgets = []
for i, contact in enumerate(Contacts):
contactWidget = QtWidgets.QWidget()
layout.addWidget(contactWidget)
contactLayout = QtWidgets.QHBoxLayout(contactWidget)
edit = QtWidgets.QLineEdit(contact.first_name)
pushButton = QtWidgets.QPushButton(f"Edit {i}")
contactLayout.addWidget(edit)
contactLayout.addWidget(pushButton)
self.contactWidgets.append((edit, pushButton))
现在,这里唯一的问题是,如果您有很多联系人,window 会长高。为避免这种情况,您可以使用 QScrollArea,但必须将其添加到中央小部件。您可以直接在 Designer 中执行此操作,因此将 QScrollArea 拖到主要 window,然后右键单击 window 的 empty space 和select 从“布局”子菜单中“垂直布局”,用 pyuic 重建 UI 并更改布局构造函数:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
layout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
self.contactWidgets = []
for i, contact in enumerate(Contacts):
# same as above
# ...
# a "spacer" at the bottom, in case there are not enough contact
# widgets to vertically fill the scroll area
layout.addStretch()
为了更好地理解如何使用 UI 文件(记住,pyuic 文件应该 永远不会 被修改),阅读更多关于关于 using Designer.
的官方指南
我正在使用 PyQt5 和 SQL 制作一个基本的联系人应用程序。打开应用程序后,我想在屏幕上显示所有联系人。所以我想为每个联系人向 UI 添加一些小部件,但我不知道在开始时会添加多少小部件(因为用户可能会通过添加或删除联系人来更改联系人数量)所以我不能手动添加它们。我用 for 循环尝试过,但由于对象的名称必须彼此不同,所以它没有用。
代码如下:
from PyQt5 import QtCore, QtGui, QtWidgets
import sqlite3
class Contact:
def __init__(self, id, first_name, last_name, phone_numbers, note = ""):
self.id = id
self.first_name = first_name
self.last_name = last_name
self.phone_numbers = phone_numbers
self.note = note
def getBoxInfo(self):
return f"{self.first_name}, {self.last_name}"
def getAllInfo(self):
if self.note != "":
return f"{self.first_name}, {self.last_name}, {self.phone_numbers}, {self.note}"
else:
return f"{self.first_name}, {self.last_name}, {self.phone_numbers}, "
#setting the connection to the database
connection = sqlite3.connect('contacts.db')
cursor = connection.cursor()
#getting 'user' and 'phone_number' datas from the database
cursor.execute("SELECT * FROM users")
connection.commit()
Users = cursor.fetchall()
cursor.execute("SELECT * FROM phone_numbers")
connection.commit()
PhoneNumbers = cursor.fetchall()
#Putting together the 'user' and 'phone_number' datas in the 'Contact' class subject and adding them to an array
Contacts = []
for i in range(len(Users)):
newContact = Contact(Users[i][0], Users[i][1], Users[i][2], list(), Users[i][3])
if newContact.note == None:
newContact.note = ""
for j in PhoneNumbers:
if j[1] == Users[i][0]:
newContact.phone_numbers.append(j[2])
Contacts.append(newContact)
#Creating the UI
class Ui_MainWindow(object):
def setupUi(self, MainWindow, Contacts):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1200, 675)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
#The part I tried to create widgets as many as 'users'
for i in range(len(Contacts)):
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(30, 30, 241, 81))
self.widget.setObjectName(f"widget{i}")
self.pushButton = QtWidgets.QPushButton(self.widget)
self.pushButton.setGeometry(QtCore.QRect(150, 20, 75, 23))
self.pushButton.setObjectName(f"pushButton{i}")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 816, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow, Contacts)
MainWindow.show()
sys.exit(app.exec_())
这个问题与对象名称无关,而是因为小部件不断添加到相同的 固定 坐标。结果是您有重叠的小部件,您只能查看最后添加的小部件。
虽然您可以使用增加的 y
位置,但这不会很好地工作:即使假设您要调整主 window 基于最后添加的小部件位置,出于多种原因,使用固定几何形状被认为是一种不好的做法;在这种特定情况下,您最终可能会得到一个太高的 window,如果您尝试调整它的大小,一些小部件将被隐藏。
解决方案是使用layout managers,确保所有内容都正确显示,并且window永远不会小于其子项所需的大小。
对于这种情况,QVBoxLayout 可能是一个不错的选择。
请注意,编辑 pyuic 生成的文件也被认为是一种不好的做法,因此我建议您在 Designer 中使用 empty main window 重新启动项目,保存UI,用 pyuic 生成文件 agan,然后在主脚本中导入该文件。在以下示例中,我假设您将该文件命名为 mainWindow_ui.py
:
from PyQt5 import QtWidgets
from mainWindow_ui import Ui_MainWindow
# ...
# contacts loading code...
# ...
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
layout = QtWidgets.QVBoxLayout(self.centralWidget())
self.contactWidgets = []
for i, contact in enumerate(Contacts):
contactWidget = QtWidgets.QWidget()
layout.addWidget(contactWidget)
contactLayout = QtWidgets.QHBoxLayout(contactWidget)
edit = QtWidgets.QLineEdit(contact.first_name)
pushButton = QtWidgets.QPushButton(f"Edit {i}")
contactLayout.addWidget(edit)
contactLayout.addWidget(pushButton)
self.contactWidgets.append((edit, pushButton))
现在,这里唯一的问题是,如果您有很多联系人,window 会长高。为避免这种情况,您可以使用 QScrollArea,但必须将其添加到中央小部件。您可以直接在 Designer 中执行此操作,因此将 QScrollArea 拖到主要 window,然后右键单击 window 的 empty space 和select 从“布局”子菜单中“垂直布局”,用 pyuic 重建 UI 并更改布局构造函数:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
layout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
self.contactWidgets = []
for i, contact in enumerate(Contacts):
# same as above
# ...
# a "spacer" at the bottom, in case there are not enough contact
# widgets to vertically fill the scroll area
layout.addStretch()
为了更好地理解如何使用 UI 文件(记住,pyuic 文件应该 永远不会 被修改),阅读更多关于关于 using Designer.
的官方指南