任务一

任务核心内容

1.界面设计实现(掌握所有Qt基础控件的使用)

2.自定义信号和槽功能使用(理解信号与槽底层工作机制)

3.布局的使用(界面自适应)

任务描述:

​ 需要实现通过列表切换页面功能,一共三个页面,

第一个页面中放置四个设备状态(使用Qlabel + QRadioButton) 分别代表机械臂、相机、plc、wcs,

第二个页面中放置四个按钮,点击按钮可以对应切换第一个页面中设备状态(即改变QRadioButton的checked状态),

第三个页面中放置QTextEdit,用来记录按钮操作。当点击按钮时增加一条信息,记录了哪个设备发生了什么变化。

任务细节

1.界面框架设计

主界面(即管理类)主要使用QListWidget和QStackWidget配合使用,在界面拖入相应控件后,通过QListWidget的currentRowChanged()信号链接到QStackWidget的setCurrentIndex()来同步切换页面。

分页面(即功能类)全部都 按照独立类的形式建立来独立实现自己的页面,通过声明类对象指针和QStackWidget的addWidget()函数来将页面添加到整体布局中。

2.功能链接

通过自定义信号和槽的形式将子类内部需要触发功能以信号的形式发送到主界面,同时主界面类可以通过分页面的类对象指针来调用分页面的公用函数,从而实现分页面之间功能的链接,且分页面之间互不干扰。

功能实现

页面设计

1,首先建立lxQtPxApp主页面,在ui文件中添加QListWidget和QStackWidget配合使用.

#include "lxQtPxApp.h"

2.建立三个分页面,并设计好页面控件.

#include "lxui_QBtnControlView.h"
#include "lxui_QDebugLog.h"
#include "lxui_QDeviceStateView.h"

功能连接

子页面切换

1,首先实现页面切换,QListWidget内置了currentRowChanged的信号,可以把当前选中列以int型emit出来.

2,声明槽函数.

	/** lxQtPxApp.h */
	void on_listwidget_row_change(const int index) const;

3,实现槽函数

	/** lxQtPxApp.cpp */

	void lxQtPxApp::on_listwidget_row_change(const int index) const
	{
	ui.stackedWidget->setCurrentIndex(index);
	}

4,在lxQtPxApp的构造函数中,实例化子页面对象

	/** 按钮控制窗口类 */
	lxui_QBtnControlView* myBtnControlView = new lxui_QBtnControlView();
	ui.stackedWidget->addWidget(myBtnControlView);			

	/** 设备列表窗口类 */
	lxui_QDeviceStateView *myDeviceStateView = new lxui_QDeviceStateView();
	ui.stackedWidget->addWidget(myDeviceStateView);	

	/** 系统日志窗口类 */
	lxui_QDebugLog  * myDebugLog = new lxui_QDebugLog();
	ui.stackedWidget->addWidget(myDebugLog);		      

5,在lxQtPxApp的构造函数中,connet信号与槽

	connect(ui.listWidget, &QListWidget::currentRowChanged,this, &qt_project::on_listwidget_row_change);

点击按钮切换设备状态

1,在按钮类lxui_QBtnControlView中设置槽函数,信号发送者为4个不同的按钮

​ 值得一提的是,经过反复优化,代码越写越精炼,很值得高兴

	void on_btn_send_signal();

2,自定义信号,可以将指向该按钮的指针作为信号的参数发送出去

	void signalSendClicked(QPushButton* btn);

3,槽函数的实现如下

	void lxui_QBtnControlView::on_btn_send_signal()
	{
		QPushButton* btn = (QPushButton*)sender();
		emit signalSendClicked(btn);
	}

4,连接按钮控件与自定义信号

	connect(ui.robotArmBtn, &QPushButton::clicked, this, &lxui_QBtnControlView::on_btn_send_signal);
	connect(ui.cameraBtn, &QPushButton::clicked, this, &lxui_QBtnControlView::on_btn_send_signal);
	connect(ui.pclBtn, &QPushButton::clicked, this, &lxui_QBtnControlView::on_btn_send_signal);	
	connect(ui.wcsBtn, &QPushButton::clicked, this, &lxui_QBtnControlView::on_btn_send_signal);

5,在设备状态类中设置槽函数

	void slot_btn_toggle_state(const QPushButton * myBtn ) const ;

6,槽函数的实现如下

	void lxui_QDeviceStateView::slot_btn_toggle_state(const QPushButton * btn) const
	{
		if ("robotPushbutton" == btn->objectName()) {

			if (ui.robotArmRBtn->isChecked())
			{
				ui.robotArmRBtn->setChecked(false);

			}
			else
			{
				ui.robotArmRBtn->setChecked(true);

			}

		}
		else if ("cameraPushbutton" == btn->objectName())
		{
			if (ui.cameraRBtn->isChecked()) {
				ui.cameraRBtn->setChecked(false);

			}
			else {
				ui.cameraRBtn->setChecked(true);

			}
		}
		else if ("pclPushbutton" == btn->objectName())
		{
			if (ui.pclRBtn->isChecked()) {
				ui.pclRBtn->setChecked(false);

			}
			else {
				ui.pclRBtn->setChecked(true);

			}
		}
		else
		{
			if (ui.wcsRBtn->isChecked()) {
				ui.wcsRBtn->setChecked(false);

			}
			else {
				ui.wcsRBtn->setChecked(true);

			}

		}
	}

7,在主页面中connet实现状态切换的信号与槽

	connect(myBtnControlView, &lxui_QBtnControlView::signalSendClicked, 
			myDeviceStateView, &lxui_QDeviceStateView::slot_btn_toggle_state);

记录设备状态变化

1,实现第二个功能的地方,每个 语句加上两句

			bool btnState = false;
			emit signalSendState(myBtn,btnState) ;

或者

			bool btnState = true;
			emit signalSendState(myBtn, btnState);

2,就能把状态信息发送出去,在主页面加入connet绑定日志类中的槽函数,即可完成数据传输

connect(myDeviceStateView, &lxui_QDeviceStateView::signalSendState, 
		       myDebugLog, &lxui_QDebugLog::slot_robot_log_state);

3,槽函数的实现如下

void lxui_QDebugLog::slot_robot_log_state(const QPushButton *myBtn, const bool btnState) const
{
	if ("robotArmBtn" == myBtn->objectName()) {
		if (!btnState) {
			QString str = "机械臂已关闭";
			ui.logTextEdit->insertPlainText(str += '\n');
		}
		else {
			QString str = "机械臂已开启";
			ui.logTextEdit->insertPlainText(str += '\n');
		}

	}
	else if ("cameraBtn" == myBtn->objectName())
	{
		if (!btnState) {
			QString str = "相机已关闭";
			ui.logTextEdit->insertPlainText(str += '\n');
		}
		else
		{
			QString str = "相机已开启";
			ui.logTextEdit->insertPlainText(str += '\n');
		}
	}
	else if ("pclBtn" == myBtn->objectName())
	{
		if (!btnState) {
			QString str = "PCL已关闭";
			ui.logTextEdit->insertPlainText(str += '\n');
		}
		else {
			QString str = "PCL已开启";
			ui.logTextEdit->insertPlainText(str += '\n');
		}
	}
	else
	{
		if (!btnState) {
			QString str = "WCS已关闭";
			ui.logTextEdit->insertPlainText(str += '\n');
		}
		else {
			QString str = "WCS已开启";
			ui.logTextEdit->insertPlainText(str += '\n');
		}
	}
	
}

至此,第一期基本上完成,前前后后大概修改了三次,第一次实现了功能,优化了代码.第二次是精炼了代码,主要是不想写重复的代码.第三次是添加了注释和修改代码的编程规范.