基本UI
- 按钮:qpushbutton
- 文本:qlabel
- 输入框:qlineedit
- w.resize重新设置大小 w,move移动窗口位置
- w.setwindowicon设置图标
- QVBoxLayout是布局,添加弹簧addStretch
- 三种窗口布局:qwidget自由度高啥都没有 qmianwindow包含菜单工具等,前一种的子类 qdialog对话框窗口基类
- 信号和槽连接:对象->信号->connect(槽函数)
- 自定义信号,pyqtsignal,需要放到__init__方法外面,类的里面
- mysign = pyqtsignal
- mysign.connect(槽函数)
- 发送信号调用:mysign.emit
- 先把显示不完的数据放到滚动对象,再把滚动对象放到布局器
上位机绘制
-
最好有别人的上位机图片,在图片上添加控件
-
去百度找,如果怕风险找公司设计部门的设计自己画
-
如果超级简单的上位机,就直接添加控件,拖上Layout整整就行
-
-
找到别人的上位机图片,在窗口插入一个List View
-
styleSheet中输入background-image: url(“./template/system overview.png”),""中的是你图片的链接
-
将List View设置为底层
-
在图片的基础上插入控件,覆盖掉图片中的控件
- 默认栅格比较大,大小和位置不好对齐,打开窗体选项卡-窗体设定-栅格,将栅格距离改小为5
- 同时控件大小最好是栅格距离的整数倍
-
上位机编写
-
信号与槽,在文件中传递搞不太明白
- 建立一个Global文件,里面放需要传递的全局变量,其他文件调用Global.变量名进行传递
- 但是可能资源被竞争,导致不可控问题
-
数据发送、接收需要在不同线程中,否则会阻塞显示线程。
-
建立Send和Receive类,继承QThread类,其中关键是类中的run方法
-
当Send.start()会自动执行run方法,所以需要在run方法内写死循环,或者使能定时器后调用self.exec_()阻塞在里面,否则就只执行一遍
-
同理,主线程在调用.show后,也会sys.exit(app.exec_())
-
-
界面互相跳转,第一个类无法使用init方法初始化第二个类,所以需要单独写一个方法,在第二个类初始化后传入第一个类
-
app.aboutToQuit.connect方法,会在关闭所有显示界面后调用一次,可以关联一些关闭操作
-
按钮比较简单一般只需要.clicked.connect,连接好点击后触发的操作即可
-
spinbox可以直接在qt designer中,设置最大最小值,点击右侧按键的步长,有效减少了值判断工作量
- 获取框中的值,直接调用.value()就可以
-
text browser缩小后不想显示滚动条,在ScrollArea中设置
- 显示值,直接调用.setText
-
解析DBC文件,安装cantools
-
显示折线图,先装PyQtChart,在界面中添加QListWidget,并调整好合适的大小
- 显示嵌套顺序:QListWidget->QListWidgetItem->QVBoxLayout->QChartView->QChart->QLineSeries
- 最好QChartView的大小根据item大小设定
- 显示关键代码如下所示
# 主文件
self.item_f = QListWidgetItem(self.P_listwidget_f)
width, height = (
self.P_listwidget_f.size().width(),
self.P_listwidget_f.size().height(),
)
self.line_chart_widget_For = LineChartWidget(
width,
height
)
self.item_f.setSizeHint(self.line_chart_widget_For.sizeHint())
self.P_listwidget_f.addItem(self.item_f)
self.P_listwidget_f.setItemWidget(self.item_f, self.line_chart_widget_For)
self.P_listwidget_f.setStyleSheet("QListWidget { border: none; }")
class LineChartWidget(QWidget):
def initChart(self):
self.series1 = QLineSeries()
self.series1.setName(self.line1name)
self.chart = QChart()
self.chart.addSeries(self.series1)
self.chart.legend().setVisible(True) # 显示图例
self.chart.legend().setAlignment(Qt.AlignRight)
self.chart.legend().setContentsMargins(0, 0, 0, 0)
self.chart.legend().setSizePolicy(
QSizePolicy.Minimum, QSizePolicy.Minimum
)
self.chart.setTitle(self.chart_title) # 设置图表标题
self.chart.createDefaultAxes() # 创建默认坐标轴
self.axis_x = self.chart.axisX()
self.axis_y = self.chart.axisY()
self.axis_x.setLabelFormat("%i") # 设置X轴标签数据类型
self.axis_x.setTitleText(self.X_title) # 设置X轴标题
self.axis_y.setLabelFormat("%i")
self.axis_y.setTitleText(self.Y_title)
self.chart_view = QChartView(self.chart) # 创建图表视图
self.chart_view.setFixedSize(
self.width + 40, self.height + 10
) # 设置图表视图大小
self.chart_view.setContentsMargins(0, 0, 0, 0) # 设置图表视图边距
layout = QVBoxLayout(self)
layout.addWidget(self.chart_view)
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
-
数据显示,关键代码如下图所示
-
data_queue1根据外部数据频率定期更新
-
updateChart也一样,需要定期调用绘制曲线
-
def updateData(self):
"""
更新数据到图表。
"""
if not self.is_paused:
self.x_value += 1
# new_data_value1 = random.randint(1, 1000)
self.data_queue1.append(self.new_data_value1)
# new_data_value2 = random.randint(1, 1000)
self.data_queue2.append(self.new_data_value2)
self.updateChart()
def updateChart(self):
min_x = self.x_value * 10 - self.max_x
max_x = self.x_value * 10
if min_x < 0:
min_x = 0
max_y = (
max(max(self.data_queue1), max(self.data_queue2)) + 5
if self.data_queue1 and self.data_queue2
else 0
)
self.axis_x.setRange(min_x, max_x) # 设置X轴范围
self.axis_x.setTickCount(7)
self.axis_y.setRange(0, max_y) # 设置Y轴范围
self.axis_y.setTickCount(7)
self.series1.clear()
for i, (value1, value2) in enumerate(zip(self.data_queue1, self.data_queue2)):
self.series1.append(i * 10, value1) # 添加数据点到线系列1