使用Qt制作一个界面在界面中添加相应的控件,绘制所需的图形,并从数据库中获取相应数据在图中绘制,具体界面如下:
大致流程:
由上图来分析出此界面所经历的流程:
首先我是将整个界面分为三个部分,分别为顶部的标题Label;中间绘制的柱状图以及坐标轴;底部的提示框以及按钮、时间等控件。
首先在主界面利用网格布局QGridLayout设置五个QGroupBox,两个按钮:呼叫和返回,以及可编辑的时间QDateTimeEdit以及一个Qlabel放置日期。并在绘图事件中绘制按钮的边框以及产出次数和异常次数的值。代码如下:
#include "Bottomwidget.h"
BottomWidget::BottomWidget(QWidget *parent)
: QWidget(parent)
{
this -> resize(1600,900);
pLabelShow = new LabelList(this);
pTableShow = new ListTable(this);//两个指针分别是自定义QWidget类的指针。
dateLabel =new QLabel(this);
BtnCall = new QPushButton(QString::fromLocal8Bit("呼叫 call"),this);
BtnReturn = new QPushButton(QString::fromLocal8Bit("返回《模具监视器》"),this);
dateEdit = new QDateTimeEdit(QDate::currentDate(), this);
QDateTime *dateTime = new QDateTime(QDateTime::currentDateTime());
QFont font;
QFont btnfont;
QFont timefont;
SNBox = new QGroupBox(QString::fromLocal8Bit("设备编号SN"),this);
OutputBox = new QGroupBox(QString::fromLocal8Bit("产出次数 Output times"),this);
NGBox = new QGroupBox(QString::fromLocal8Bit("异常次数 NG output"),this);
CycleBox = new QGroupBox(QString::fromLocal8Bit("生产周期 Cycle"),this);
NameBox = new QGroupBox(QString::fromLocal8Bit("当前生产(设备/产品)名称:"),this);
QGridLayout *Layout = new QGridLayout(this);
timefont.setPointSize(12);
btnfont.setPointSize(15);
font.setPointSize(25);
SNBox -> setFixedSize(280,120);
OutputBox -> setFixedSize(260,120);
NGBox -> setFixedSize(280,120);
CycleBox -> setFixedSize(240,120);
NameBox -> setFixedSize(300,120);
QString str = dateTime -> toString("yyyy-MM-dd hh:mm:ss ddd");
dateLabel -> setText(str);
dateLabel -> setFixedSize(250,60);
dateLabel -> setFont(timefont);
dateLabel -> show();
dateEdit -> setMinimumDate(QDate::currentDate().addDays(-365)); // -365天
dateEdit -> setMaximumDate(QDate::currentDate().addDays(365)); // +365天
dateEdit -> setCalendarPopup(true); // 日历弹出
dateEdit -> setFixedSize(300,60);
dateEdit -> setStyleSheet("background-color: rgb(236,236,236)");
dateEdit -> setAlignment(Qt::AlignCenter);
dateEdit -> setFont(font);
BtnCall -> setStyleSheet("background-color: rgb(255,173,91)");
BtnCall -> setFixedSize(400,60);
BtnCall -> setFont(btnfont);
BtnReturn -> setStyleSheet("background-color: rgb(0,255,64)");
BtnReturn -> setFixedSize(400,60);
BtnReturn ->setFont(btnfont);
Layout -> addWidget(NameBox, 9,8,1,2,Qt::AlignLeft| Qt::AlignBottom);
//Layout -> setMargin(12);
Layout -> addWidget(pLabelShow,0,0,1,11,Qt::AlignTop);
Layout -> addWidget(pTableShow,0,0,12,12);
Layout -> addWidget(BtnCall,10,0,1,3,Qt::AlignLeft | Qt::AlignBottom);
Layout -> addWidget(dateEdit,10,3,1,3,Qt::AlignBottom|Qt::AlignCenter);
Layout -> addWidget(dateLabel,10,6,1,3,Qt::AlignCenter|Qt::AlignBottom);
Layout -> addWidget(BtnReturn,10,9,1,3,Qt::AlignRight |Qt::AlignBottom);
Layout -> addWidget(SNBox, 9,0,1,2,Qt::AlignLeft| Qt::AlignBottom);
Layout -> addWidget(OutputBox, 9,2,1,2,Qt::AlignLeft| Qt::AlignBottom);
Layout -> addWidget(NGBox, 9,4,1,2,Qt::AlignLeft| Qt::AlignBottom);
Layout -> addWidget(CycleBox, 9,6,1,2,Qt::AlignLeft| Qt::AlignBottom);
Layout -> setRowStretch(0,1);//行延展
Layout -> setSpacing(5);//控件间距
Layout -> setMargin(0);//边距
}
BottomWidget::~BottomWidget()
{
}
void BottomWidget::paintEvent(QPaintEvent *ev)
{
QPainter p(this);
QPen PenRect;
PenRect.setWidth(2);
PenRect.setColor(QColor(0,0,0));
PenRect.setStyle(Qt::DotLine);
p.setPen(PenRect);
p.drawRect(dateEdit ->x(),dateEdit ->y(),300,60);
p.drawRect(BtnCall -> x(),BtnCall -> y(),400,60);
p.drawRect(BtnReturn ->x() ,BtnReturn->y(),400,60);//绘制按钮以及时间边框
QFont font;
font.setPointSize(25);
QPen PenNum;
PenNum.setColor(QColor(0,255,0));
PenRect.setStyle(Qt::SolidLine);
p.setPen(PenNum);
p.setFont(font);
int OPT_total = 0;//Output times,产出次数总数
int NGT_total =0;//NG times,异常次数的总数
for(int i = 0;i<24;i++)
{
OPT_total = OPT_total + pTableShow ->Output_times[i];
NGT_total = NGT_total + pTableShow ->NG_times[i];
}
QString str = QString("%1").arg(OPT_total);
p.drawText(OutputBox ->x()+90,OutputBox ->y()+80,str);
p.setPen(QPen(QColor(255,0,0)));
p.setFont(font);
QString str1 = QString("%1").arg(NGT_total);
p.drawText(NGBox ->x()+90,NGBox ->y()+80,str1);
}
void BottomWidget::resizeEvent(QResizeEvent *event)//当窗口发生变化时自动调用resizeEvent
{
QWidget::resizeEvent(event);
this -> update();//刷新图,间接调用paintevent
}
在LabelList中绘制顶部的标题等内容。
#include "Labellist.h"
LabelList::LabelList(QWidget *parent) : QWidget(parent)
{
//this -> resize(1600,900);
label1 = new QLabel(QString::fromLocal8Bit("24小时日志|白/夜班日志|"),this);
label2 = new QLabel(QString::fromLocal8Bit("模具监视器&生产看板"),this);
label3 = new QLabel(QString::fromLocal8Bit("网络状态:已断开!"),this);
label4 = new QLabel(QString::fromLocal8Bit("网络状态:运行中!"),this);
label5 = new QLabel(QString::fromLocal8Bit("异常次数"),this);
label6 = new QLabel(QString::fromLocal8Bit("产出次数"),this);
pLayout = new QGridLayout(this);
QFont font1;
QFont font2;
QFont font3("Microsoft YaHei",25,75);
QPalette p1;
QPalette p2;
p1.setColor(QPalette::WindowText,Qt::red);
p2.setColor(QPalette::WindowText,Qt::green);
font1.setPointSize(25);
font2.setPointSize(20);
label1 -> setFont(font2);
label1 -> setFixedWidth(380);
label2 -> setFont(font3);
label3 -> setPalette(p1);
label3 -> setFixedWidth(150);
label4 -> setPalette(p2);
label4 -> setFixedWidth(150);
init();
}
void LabelList::init()
{
pLayout -> addWidget(label1,0,0,2,3,Qt::AlignLeft | Qt::AlignTop);
pLayout -> addWidget(label2,0,5,2,4,Qt::AlignTop|Qt::AlignCenter);
pLayout -> addWidget(label3,0,9,1,1,Qt::AlignBottom);
pLayout -> addWidget(label4,1,9,1,1,Qt::AlignTop);
pLayout -> addWidget(label5,1,11,1,1,Qt::AlignRight);
pLayout -> addWidget(label6,1,12,1,1,Qt::AlignTop|Qt::AlignCenter);
pLayout -> setRowStretch(0,1);
pLayout -> setSpacing(5);
this -> setLayout(pLayout);
}
void LabelList::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setBrush(QBrush(QColor(255,0,0)));
p.drawRect(label5->x()-35,label5->y(),30,15);
p.setBrush(QBrush(QColor(0,255,0)));
p.drawRect(label6->x()-35,label6->y(),30,15);//画顶部异常次数和产出次数的框
}
void LabelList::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
this -> update();
}
在ListTable中绘制中间的网格坐标以及柱状图:
```cpp
#include "listtable.h"
ListTable::ListTable(QWidget *parent) : QWidget(parent)
{
pDataport = new DataPort(this);//自定义的QWidget类,即数据端口类
max = 0;
for(int i = 0;i<=24;i++)
{
Output_times[i] = pDataport ->Output_times[i];
NG_times[i] = pDataport -> NG_times[i];//从数据端口类中获取数据库中的产出次数的值以及NG次数的值。
if(max<(Output_times[i]+NG_times[i]))
max = Output_times[i]+NG_times[i];//获取24小时中产出次数加NG次数的最大值
}
}
void ListTable::paintEvent(QPaintEvent *)
{
int m_w = width();
int m_h = height();//获取窗口宽高
QFont font;
font.setBold(true);//设置粗体字
QPainter p(this);
QPen PenLine;
PenLine.setWidth(2);
PenLine.setColor(QColor(0,0,0));
PenLine.setStyle(Qt::DotLine);
p.setPen(PenLine);
int LineNum = max/50;//设置x方向上的线条数,由于我设置的刻度为50一条线,所以先判断NG次数以及产出次数和的最大值,从而设置出x方向的线条数量。
if(max % 50)
LineNum = LineNum+1;
if(LineNum <3 )
LineNum = 3;当和小于150时,x方向的线条固定为4条(0,1,2,3)
for(int i=0;i<=LineNum;i++)
{
QString str = tr("%1").arg((LineNum-i)*50);
p.drawText(10,m_h/5*3/LineNum*i+137,str);//绘制刻度值
p.drawLine(40,m_h/5*3/LineNum*i+140,50+m_w/25*24,m_h/5*3/LineNum*i+140);//绘制横线
}
for(int i = 0;i<=24;i++)
{
QString str = tr("%1").arg(i);
p.drawText(47+m_w/25*i,m_h/5*3+160,str);//绘制纵坐标刻度,即0-24小时
p.drawLine(50+m_w/25*i,140,50+m_w/25*i,m_h/5*3+145);//绘制纵线
}
p.setPen(QPen(QColor(0,0,0)));
for(int i = 24;i>=0;i--)//绘制柱状图
{
int OPT_Height = Output_times[24-i]/(LineNum*50)*3*m_h/5;
int NGT_Height = NG_times[24-i]/(LineNum*50)*3*m_h/5;//从数据库中获取的值需要先转化成图上相应的比例的值。
int j=0;//防止NG次数值的显示与产出次数值显示不重叠
QString str = tr("%1").arg(Output_times[24-i]);
QString str1 = tr("%1").arg(NG_times[24-i]);
if(OPT_Height<12)
{
j=12;
}
if(i==24)//当0点时绘制的柱状图比其余时间要更窄
{
p.setBrush(QBrush(QColor(0,255,0)));
p.drawRect(40,m_h/5*3+140-OPT_Height,30,OPT_Height);
p.setBrush(QBrush(QColor(255,0,0)));
p.drawRect(40,m_h/5*3+140-OPT_Height-NGT_Height,30,NGT_Height);
p.setPen(QPen(QColor(0,0,0)));
p.setFont(font);
p.drawText(43,(m_h/5*3+140)-OPT_Height-NGT_Height/2-j,str1);
p.drawText(43,(m_h/5*3+140)-OPT_Height/2,str);
continue;
}
if(i == 0)
continue;
//绘制1-23小时的柱状图以及对应的值
p.setBrush(QBrush(QColor(0,255,0)));
p.drawRect(30+m_w/25*(24-i),m_h/5*3+140-OPT_Height,40,OPT_Height);
p.setBrush(QBrush(QColor(255,0,0)));
p.drawRect(30+m_w/25*(24-i),m_h/5*3+140-OPT_Height-NGT_Height,40,NGT_Height);
p.setPen(QPen(QColor(0,0,0)));
p.setFont(font);
p.drawText(37+m_w/25*(24-i),(m_h/5*3+140)-OPT_Height-NGT_Height/2-j,str1);
p.drawText(37+m_w/25*(24-i),(m_h/5*3+140)-OPT_Height/2,str);
}
}
void ListTable::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
this -> update();
}
在数据端口的类中实现模型与数据库信息的交互:
#include "dataport.h"
DataPort::DataPort(QWidget *parent) : QWidget(parent)
{
init();
}
void DataPort::init()
{
Data *pData = new Data(this);
pData -> init();
//QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("select * from DataValue");
// int value_i = 0;
// while(query.next())
// {
// Output_times[value_i] = query.value(1).toInt();
// NG_times[value_i++] = query.value(2).toInt();
// }
double OPT_array[25] = {30, 1, 2, 3, 4,
5, 6, 7, 8, 9,
10, 11, 12, 13,
14, 15, 16, 17, 18,
19, 20, 21, 22, 0};
double NGT_array[25] = { 55, 1, 2, 3, 4,
5, 6, 7, 8, 9,
10, 11, 12, 13, 14,
15, 16, 17, 18, 19,
20, 21, 22, 23, 0};//两个数组来设置产出次数和NG次数的值
for(int i =0;i<25;i++)
{
Output_times[i] = OPT_array[i];
NG_times[i] = NGT_array[i];
}
for(int i =0;i<25;i++)//将产出次数和NG次数的值赋给全局数组。
{
QString OPT_str =QString("update DataValue set OutputValue = '%1' where id = %2").arg(Output_times[i]).arg(i);
query.exec(OPT_str);
}
}
设置数据库:
#include "Data.h"
Data::Data(QWidget *parent) : QWidget(parent)
{
init();
}
void Data::init()
{
QVariantList id;
id<<0<<1<<2<<3<<4
<<5<<6<<7<<8<<9
<<10<<11<<12<<13<<14
<<15<<16<<17<<18<<19
<<20<<21<<22<<23<<24;
QVariantList OutputValues;
OutputValues<<100<<0<<2<<3<<4
<<5<<6<<7<<8<<9
<<10<<11<<12<<13<<14
<<15<<16<<17<<18<<19
<<20<<21<<22<<23<<24;
QVariantList NGValues;
NGValues<<10<<0<<2<<3<<4
<<5<<6<<7<<8<<9
<<10<<11<<12<<13<<14
<<15<<16<<17<<18<<19
<<20<<21<<22<<23<<24;
QSqlDatabase db;
//在Qt上使用SQLite的时候,如果第二次使用QSqlDatabase::addDatabase()方式时,就会出现以下错误提示:
//QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
//所以先判断一下这个默认的连接名是否存在,如果不存在才使用addDatabase()方法,如果存在则使用database()方法
if(QSqlDatabase::contains("qt_sql_default_connection"))
db = QSqlDatabase::database("qt_sql_default_connection");
else
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if(!db.open())
{
QMessageBox::warning(0,"error",db.lastError().text());
return;
}
QSqlQuery query;
query.exec("create table DataValue(id int primary key, OutputValue int, NGValue int)");//创建数据库
query.prepare("insert into DataValue (id,OutputValue,NGValue) values (:id,:OutputValue,:NGValue)");//插入数据库的值
query.bindValue(":id",id );
query.bindValue(":OutputValue", OutputValues);
query.bindValue(":NGValue", NGValues);
query.execBatch(); //加入库中
}