在我的基于 WxPython 的跨平台框架完成后,对 WxPython 的灵活性以及强大功能有了很深的了解,在跨平台的桌面应用上我突然对 PyQt6 的开发也感兴趣,于是准备了开发环境学习 PyQt 6,并对比下 WxPython 的差异来进行深入的了解,发现它们很多理念和做法是如此的类似。
1、pyqt6 都有那些布局控件?
PyQt6 提供了多种布局控件,帮助开发者轻松地将界面元素排列在窗口中。对比发现它们和 WxPython 简直是双胞胎一样非常相似,以下是常用的布局控件及其简要介绍:
1) QHBoxLayout (水平布局)
QHBoxLayout
是一个水平布局管理器,它会将窗口中的控件从左到右地排列。
from PyQt6.QtWidgets import QWidget, QHBoxLayout, QPushButton
widget = QWidget()
layout = QHBoxLayout()
layout.addWidget(QPushButton('Button 1'))
layout.addWidget(QPushButton('Button 2'))
widget.setLayout(layout)
widget.show()
复制代码
2)QVBoxLayout (垂直布局)
QVBoxLayout
是一个垂直布局管理器,它会将控件从上到下地排列。
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton
widget = QWidget()
layout = QVBoxLayout()
layout.addWidget(QPushButton('Button 1'))
layout.addWidget(QPushButton('Button 2'))
widget.setLayout(layout)
widget.show()
复制代码
3)QGridLayout (网格布局)
QGridLayout
是一个网格布局管理器,控件被排列在一个网格中,类似于表格。
from PyQt6.QtWidgets import QWidget, QGridLayout, QPushButton
widget = QWidget()
layout = QGridLayout()
layout.addWidget(QPushButton('Button 1'), 0, 0)
layout.addWidget(QPushButton('Button 2'), 0, 1)
layout.addWidget(QPushButton('Button 3'), 1, 0)
widget.setLayout(layout)
widget.show()
复制代码
在 PyQt6 中,类似于 wxPython 的 GridBagSizer,即可以让控件跨行和跨列的布局功能,通常通过使用 QGridLayout
来实现。QGridLayout
允许你指定控件的位置和它们所占的行列范围,从而实现跨行和跨列的布局。
QGridLayout
是 PyQt6 中的网格布局管理器,它允许控件按行列排列,你可以通过指定控件所在的行和列来控制它们的位置。如果需要让控件跨越多个行或列,可以通过设置控件的 rowSpan
和 columnSpan
来实现。
# 添加控件,指定位置 (行, 列) 以及跨越的行和列
layout.addWidget(QPushButton('Button 1'), 0, 0) # 第 1 个按钮
layout.addWidget(QPushButton('Button 2'), 0, 1) # 第 2 个按钮
layout.addWidget(QPushButton('Button 3'), 1, 0, 1, 2) # 第 3 个按钮跨越 1 行 2 列
复制代码
你还可以根据需求自由配置控件在 QGridLayout
中的位置,包括:
4)QFormLayout (表单布局)
QFormLayout
用于创建一个表单式的布局,控件和标签按“标签-控件”对的形式排列。
from PyQt6.QtWidgets import QWidget, QFormLayout, QLabel, QLineEdit
widget = QWidget()
layout = QFormLayout()
layout.addRow(QLabel('Name:'), QLineEdit())
layout.addRow(QLabel('Age:'), QLineEdit())
widget.setLayout(layout)
widget.show()
复制代码
5)QStackedLayout (堆叠布局)
QStackedLayout
允许多个控件堆叠在一起,且一次只显示其中一个控件。
from PyQt6.QtWidgets import QWidget, QStackedLayout, QPushButton
widget = QWidget()
layout = QStackedLayout()
layout.addWidget(QPushButton('Page 1'))
layout.addWidget(QPushButton('Page 2'))
widget.setLayout(layout)
widget.show()
# 切换页面
layout.setCurrentIndex(1) # 切换到 Page 2
复制代码
6)QSplitter (分割器)
QSplitter
允许用户通过拖动分隔条来调整控件的大小。通常用于布局中需要用户可调整分配空间的控件。
from PyQt6.QtWidgets import QWidget, QSplitter, QVBoxLayout, QPushButton
from PyQt6.QtCore import Qt
widget = QWidget()
layout = QVBoxLayout()
splitter = QSplitter(Qt.Orientation.Horizontal)
splitter.addWidget(QPushButton('Button 1'))
splitter.addWidget(QPushButton('Button 2'))
layout.addWidget(splitter)
widget.setLayout(layout)
widget.show()
复制代码
如果对多个窗口放置在 Splitter 控件里面, 可以得到如下界面。
7)QBoxLayout (基础布局,QHBoxLayout 和 QVBoxLayout 的基类)
QBoxLayout
是 QHBoxLayout
和 QVBoxLayout
的基类,可以选择水平或垂直方向来排列控件。
from PyQt6.QtWidgets import QWidget, QBoxLayout, QPushButton
from PyQt6.QtCore import Qt
widget = QWidget()
layout = QBoxLayout(QBoxLayout.Direction.LeftToRight)
layout.addWidget(QPushButton('Button 1'))
layout.addWidget(QPushButton('Button 2'))
widget.setLayout(layout)
widget.show()
复制代码
PyQt6 提供了多种布局管理器,能够灵活地处理不同控件之间的关系。常见的布局管理器包括 QHBoxLayout
、QVBoxLayout
、QGridLayout
、QFormLayout
等。不同的布局管理器适用于不同的场景,帮助开发者更好地控制控件的排列和显示方式。
我整理了以上的代码,并且整合上面所有布局的案例代码在一个界面上,如下所示效果。
而且 PyQT6 可以通过样式设置一些特别的效果,如下所示。
可以通过 setStyle 或者 setStyleSheet 函数方式指定不同的界面效果。
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion') # 设置样式
# app.setStyle('Windows')
# app.setStyle('WindowsVista')
# app.setStyle('Macintosh')
# app.setStyle('GTK')
# app.setStyle('CleanLooks')
# app.setStyle('Plastique')
# 设置背景颜色
# app.setStyleSheet("QWidget { background-color: white; }")
app.setStyleSheet("""
QPushButton {
background-color: #008CBA;
color: white;
font-size: 16px;
padding: 10px 20px;
border-radius: 5px;
border: 2px solid #006F8C;
}
QPushButton:hover {
background-color: #006F8C;
border: 2px solid #008CBA;
}
QPushButton:pressed {
background-color: #004F68;
border: 2px solid #006F8C;
}
""")
# 创建窗口对象
form = QWidgetExample()
form.show()# 启动应用程序的事件循环
sys.exit(app.exec())
复制代码
如果我们需要类似一个主窗口界面那样,可以实现如下效果。
2、我对 wxpython 的控件比较了解,如果学习 pyqt6,如何入手,对比介绍一下
如果你已经对 wxPython 的控件比较熟悉,学习 PyQt6 会变得更加容易,因为这两个框架在很多方面有相似之处,但 PyQt6 提供了更多的功能和灵活性,尤其是在与 Qt 的集成方面。为了帮助你更顺利地过渡,下面我会通过对比两者来介绍 PyQt6 的核心概念和控件。
1)应用程序和窗口
# wxPython
import wx
app = wx.App(False)
frame = wx.Frame(None, wx.ID_ANY, "Hello wxPython")
frame.Show()
app.MainLoop()
复制代码
# PyQt6
from PyQt6.QtWidgets import QApplication, QMainWindow
app = QApplication([])
window = QMainWindow()
window.setWindowTitle('Hello PyQt6')
window.show()
app.exec()
复制代码
2) 布局管理
# wxPython
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(wx.Button(frame, label="Button 1"))
sizer.Add(wx.Button(frame, label="Button 2"))
frame.SetSizer(sizer)
复制代码
# PyQt6
from PyQt6.QtWidgets import QVBoxLayout, QPushButton
layout = QVBoxLayout()
layout.addWidget(QPushButton("Button 1"))
layout.addWidget(QPushButton("Button 2"))
window.setLayout(layout)
复制代码
上面 PyQt6 程序截图的案例,我综合了各个 PyQT6 的各个布局处理,整合在一个窗口里面,代码如下所示。
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QToolBar, QStatusBar, QMenuBar, QDialog, QLabel, QLineEdit, QTextEdit, QPushButton
from PyQt6.QtGui import QAction, QIcon # 导入 QIcon 用于设置图标
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QLayout, QBoxLayout, QHBoxLayout, QVBoxLayout,QGridLayout, QFormLayout, QStackedLayout, QSplitter, QScrollArea, QSizePolicy, QSpacerItem, QSizePolicy, QMessageBox
class QWidgetExample(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('QWidget Example')
# QBoxLayout
# main_layout = QBoxLayout(QBoxLayout.Direction.LefoRight) # 0
main_layout = QVBoxLayout() #1
btn_widget = QWidget()
layout_btn = QHBoxLayout() #2
layout_btn.addWidget(QPushButton('Button 1'), stretch=1)
layout_btn.addWidget(QPushButton('Button 2'))
btn_widget.setLayout(layout_btn)
main_layout.addWidget(btn_widget)
# QGridLayout
grid_widget = QWidget()
layout_grid = QGridLayout() #3
layout_grid.addWidget(QPushButton('Button 1'), 0, 0)
layout_grid.addWidget(QPushButton('Button 2'), 0, 1)
layout_grid.addWidget(QPushButton('Button 3'), 1, 0, 1, 2) # 第 3 个按钮跨越 1 行 2 列
grid_widget.setLayout(layout_grid)
main_layout.addWidget(grid_widget)
#form layout
form_widget = QWidget()
layout_form = QFormLayout() #4
layout_form.addRow(QLabel('Name:'), QLineEdit(placeholderText='Enter your name'))
layout_form.addRow(QLabel('Age:'), QLineEdit( text='25', readOnly=True))
layout_form.addRow(QLabel('Note:'), QTextEdit(placeholderText='Enter your note'))
button = QPushButton('Submit')
button.setToolTip('Click to submit')
button.clicked.connect(self.on_button_click)
layout_form.addRow(button)
# 设置字段增长策略,使输入控件可以拉伸
layout_form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
form_widget.setLayout(layout_form)
# 添加到布局中
main_layout.addWidget(form_widget)
#stacked layout
stacked_widget = QWidget()
layout_stacked = QStackedLayout() #5
layout_stacked.addWidget(QPushButton('Page 1'))
layout_stacked.addWidget(QPushButton('Page 2'))
# 切换页面
layout_stacked.setCurrentIndex(1) # 切换到 Page 2
stacked_widget.setLayout(layout_stacked)
main_layout.addWidget(stacked_widget)
#QSplitter
splitter_widget = QWidget()
layout_splitter = QVBoxLayout()
splitter = QSplitter(Qt.Orientation.Horizontal)
splitter.addWidget(QPushButton('Left'))
splitter.addWidget(QPushButton('Right'))
layout_splitter.addWidget(splitter)
layout_splitter.setStretchFactor(splitter, 1)
splitter_widget.setLayout(layout_splitter)
main_layout.addWidget(splitter_widget)
self.setLayout(main_layout)
def on_button_click(self):
print('Button clicked')
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.StandardButton.Yes |
QMessageBox.StandardButton.No, QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion') # 设置样式
# 创建窗口对象
form = QWidgetExample()
form.show()# 启动应用程序的事件循环
sys.exit(app.exec())
复制代码
3) 事件和信号槽机制
# wxPython
button.Bind(wx.EVT_BUTTON, on_button_click)
复制代码
# PyQt6
button.clicked.connect(on_button_click)
复制代码
4) 控件和小部件
PyQt6:
提供的常用控件有:QPushButton
, QTextEdit
, QListView
, QComboBox
等。
PyQt6 的控件通常会比 wxPython 的控件具有更多的功能和更丰富的自定义选项。
# wxPython
text_ctrl = wx.TextCtrl(frame)
复制代码
# PyQt6
text_edit = QTextEdit()
复制代码
5) 对话框和模态
# wxPython
dialog = wx.MessageDialog(frame, "Hello", "Greeting", wx.OK)
dialog.ShowModal()
复制代码
# PyQt6
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QPushButton
dialog = QDialog()
layout = QVBoxLayout()
layout.addWidget(QPushButton('OK'))
dialog.setLayout(layout)
dialog.exec()
复制代码
6) 样式和主题
# wxPython
frame.SetBackgroundColour(wx.Colour(255, 255, 255))
复制代码
# PyQt6
app.setStyleSheet("QWidget { background-color: white; }")
复制代码
3、wxpython 中的 wx.MessageBox 消息对话框,以及打开文件对话框、字体对话框、颜色对话框等常用对话框,如何在 PyQT6 中实现
在 PyQt6 中,你可以使用 QMessageBox
来替代 wxPython 中的 wx.MessageBox
,并使用不同的对话框组件来替代文件选择对话框、字体对话框、颜色对话框等。下面是这些常用对话框在 PyQt6 中的实现示例:
1) 消息对话框 (QMessageBox
)
在 PyQt6 中,你可以使用 QMessageBox
来创建类似于 wx.MessageBox
的消息框。
from PyQt6.QtWidgets import QApplication, QMessageBox, QPushButton
def show_message_box():
app = QApplication([])
# 创建消息对话框
msg = QMessageBox()
msg.setIcon(QMessageBox.Icon.Information) # 设置图标
msg.setText("This is an info message.")
msg.setWindowTitle("Info")
msg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel)
# 显示对话框并获取响应
response = msg.exec()
if response == QMessageBox.StandardButton.Ok:
print("OK clicked")
else:
print("Cancel clicked")
app.exec()
show_message_box()
复制代码
2)打开文件对话框 (QFileDialog
)
在 PyQt6 中,QFileDialog
用于打开和保存文件,类似于 wxPython 中的 wx.FileDialog
。
from PyQt6.QtWidgets import QApplication, QFileDialog, QPushButton
def open_file_dialog():
app = QApplication([])
# 创建打开文件对话框
options = QFileDialog.Option.ReadOnly
file_name, _ = QFileDialog.getOpenFileName(None, "Open File", "", "All Files (*)", options=options)
if file_name:
print(f"File selected: {file_name}")
else:
print("No file selected")
app.exec()
open_file_dialog()
复制代码
3) 字体对话框 (QFontDialog
)
QFontDialog
用于选择字体,在 PyQt6 中的使用方式类似于 wxPython 中的 wx.FontDialog
。
from PyQt6.QtWidgets import QApplication, QFontDialog, QPushButton
def font_dialog():
app = QApplication([])
# 创建字体对话框
font, ok = QFontDialog.getFont()
if ok:
print(f"Selected font: {font.family()}, size: {font.pointSize()}")
else:
print("No font selected")
app.exec()
font_dialog()
复制代码
4)颜色对话框 (QColorDialog
)
QColorDialog
用于选择颜色,类似于 wxPython 中的 wx.ColourDialog
。
from PyQt6.QtWidgets import QApplication, QColorDialog, QPushButton
def color_dialog():
app = QApplication([])
# 创建颜色对话框
color = QColorDialog.getColor()
if color.isValid():
print(f"Selected color: {color.name()}")
else:
print("No color selected")
app.exec()
color_dialog()
复制代码
5) 文件保存对话框 (QFileDialog
)
保存文件对话框也使用 QFileDialog
,通过指定保存选项来实现。
from PyQt6.QtWidgets import QApplication, QFileDialog
def save_file_dialog():
app = QApplication([])
# 创建保存文件对话框
file_name, _ = QFileDialog.getSaveFileName(None, "Save File", "", "Text Files (*.txt);;All Files (*)")
if file_name:
print(f"File will be saved as: {file_name}")
else:
print("No file selected for saving")
app.exec()
save_file_dialog()
复制代码
在 wxPython 中,可以使用 wx.DirDialog
来选择目录。在 PyQt6 中,QFileDialog
也支持目录选择,只需要指定 FileMode
为 QFileDialog.Directory
。
from PyQt6.QtWidgets import QApplication, QFileDialog, QPushButton
def directory_dialog():
app = QApplication([])
# 创建选择目录的对话框
directory = QFileDialog.getExistingDirectory(None, "Select Directory")
if directory:
print(f"Selected directory: {directory}")
else:
print("No directory selected")
app.exec()
directory_dialog()
复制代码
总结
wx.MessageBox
-> QMessageBox
wx.FileDialog
-> QFileDialog
(同样用于打开和保存文件)
wx.FontDialog
-> QFontDialog
wx.ColourDialog
-> QColorDialog
这些对话框的功能和 PyQt6 中的相应控件类似,基本上可以通过这些标准控件实现与 wxPython 相同的效果。
4、wxpython 的控件和 pyQT 的常用控件对比一下
常用控件包括标签、单行文本、多行文本、日期、数值、单选框、复选框、Combobox 下拉列表、树形下拉列表、图片显示等常用控件。
以下是 wxPython 和 PyQt6 中常用控件的对比,涵盖标签、文本框、日期、数值、单选框、复选框、下拉列表、树形控件、图片显示等控件的对应关系及其使用示例。
1) 标签(Label)
2)单行文本框(Single-line Text)
3)多行文本框(Multi-line Text)
4)日期选择框(Date Picker)
5)数值输入框(Number Input)
6)单选框(Radio Button)
wx.RadioBox
是一个带有多个单选按钮的控件,允许用户在多个选项中选择一个。在 PyQt6 中,可以使用 QRadioButton
与 QButtonGroup
来实现类似的效果。
7) 复选框(Check Box)
wxPython: 使用 wx.CheckBox
PyQt6: 使用 QCheckBox
wx.CheckListBox
允许用户在多个选项中选择多个项。PyQt6 中没有直接对应的控件,但可以使用 QCheckBox
和布局控件组合来实现类似的效果。
如果要实现类似 FieldSet 的效果,如下所示。
代码如下所示
from PyQt6.QtWidgets import QApplication, QWidget, QRadioButton, QCheckBox, QVBoxLayout, QGroupBox, QButtonGroup, QFormLayout
from PyQt6.QtCore import Qt
class FieldSetExample(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("FieldSet Example")
# 创建单选按钮
self.radio1 = QRadioButton("Option 1")
self.radio2 = QRadioButton("Option 2")
# 创建复选框
self.check1 = QCheckBox("Additional Option 1")
self.check2 = QCheckBox("Additional Option 2")
# 创建按钮组以保证单选功能
self.button_group = QButtonGroup(self)
self.button_group.addButton(self.radio1)
self.button_group.addButton(self.radio2)
# 创建 QGroupBox 来实现 FieldSet 效果
group_box = QGroupBox("Select Your Options") # 设置标题
layout = QVBoxLayout()
layout.addWidget(self.radio1)
layout.addWidget(self.radio2)
group_box.setLayout(layout)
# 创建另一个 QGroupBox 来显示复选框
check_box_group = QGroupBox("Additional Options")
check_layout = QVBoxLayout()
check_layout.addWidget(self.check1)
check_layout.addWidget(self.check2)
check_box_group.setLayout(check_layout)
# 设置主布局
main_layout = QFormLayout()
main_layout.addWidget(group_box)
main_layout.addWidget(check_box_group)
self.setLayout(main_layout)
# 显示窗口
self.show()
app = QApplication([])
window = FieldSetExample()
app.exec()
复制代码
8)下拉列表(ComboBox)
wxPython: 使用 wx.ComboBox
PyQt6: 使用 QComboBox
在 QComboBox
中添加自定义对象,如果对象类是 CListItem(Text, Value)
,可以通过将对象作为 QComboBox
的项来存储。你可以创建一个自定义的类(例如 CListItem
),并使用 addItem()
方法将自定义对象添加到 QComboBox
中。
为了将 CListItem
添加到 QComboBox
,你需要确保在添加项时使用自定义的文本显示,而在获取选中项时能够正确地获取到对应的 Value
。
from PyQt6.QtWidgets import QApplication, QWidget, QComboBox, QVBoxLayout
from PyQt6.QtCore import Qt
class CListItem:
def __init__(self, text, value):
self.text = text
self.value = value
def __repr__(self):
return f"CListItem(text={self.text}, value={self.value})"
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
layout = QVBoxLayout(self)
# 创建 QComboBox
combo = QComboBox(self)
# 创建自定义对象 CListItem 并添加到 QComboBox
item1 = CListItem("Item 1", 100)
item2 = CListItem("Item 2", 200)
item3 = CListItem("Item 3", 300)
# 使用 addItem 添加文本显示的同时存储 CListItem 对象
combo.addItem(item1.text, item1) # item1.text 是显示文本,item1 是存储对象
combo.addItem(item2.text, item2) # item2.text 是显示文本,item2 是存储对象
combo.addItem(item3.text, item3) # item3.text 是显示文本,item3 是存储对象
# 连接槽函数,获取选中的 CListItem 对象
combo.currentIndexChanged.connect(self.on_combobox_changed)
# 将 QComboBox 添加到布局中
layout.addWidget(combo)
self.setLayout(layout)
def on_combobox_changed(self, index):
# 获取当前选中的 CListItem 对象
combo = self.sender()
item = combo.itemData(index)
if item:
print(f"Selected item: {item} with value {item.value}")
app = QApplication([])
window = MyWindow()
window.setWindowTitle("QComboBox with Custom Objects")
window.resize(300, 150)
window.show()
app.exec()
复制代码
9)树形控件(Tree Control)
10)图片显示(Image Display)
总结
通过这些对比,你可以更容易地在 PyQt6 中找到对应的控件,并使用相似的方式构建用户界面。
文章转载自:伍华聪
原文链接:https://www.cnblogs.com/wuhuacong/p/18663003
体验地址:http://www.jnpfsoft.com/?from=001YH
评论