文章目录
前言
1.水平布局、垂直布局、网格布局均放置于QGroupBox中。
2.继承QWidget类,在构造函数中调用setLayout()函数,即可完成布局。
一、水平布局(QHBoxLayout)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
//, ui(new Ui::MainWindow)
{
//ui->setupUi(this);
//this->setWindowFlags(Qt::FramelessWindowHint);
this->resize(1022,670);
createMenu();
createHorizontalGroupBox();
createGridGroupBox();
createFormGroupBox();
//! [0]
//! [1]
bigEditor = new QTextEdit;
bigEditor->setPlainText(tr("This widget takes up all the remaining space "
"in the top-level layout."));
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
| QDialogButtonBox::Cancel);
//! [1]
//! [2]
QVBoxLayout *mainLayout = new QVBoxLayout;
//! [2] //! [3]
mainLayout->setMenuBar(menuBar);
//! [3] //! [4]
mainLayout->addWidget(horizontalGroupBox);
mainLayout->addWidget(gridGroupBox);
mainLayout->addWidget(formGroupBox);
mainLayout->addWidget(bigEditor);
mainLayout->addWidget(buttonBox);
//! [4] //! [5]
this->setLayout(mainLayout);
setWindowTitle(tr("Basic Layouts"));
}
//! [6]
void MainWindow::createMenu()
{
menuBar = new QMenuBar;
// menuBar->setParent(this);
fileMenu = new QMenu(tr("&File"));
exitAction = fileMenu->addAction(tr("Exit"));
menuBar->addMenu(fileMenu);
// connect(exitAction, &QAction::triggered, this, &MainWindow::accept);
}
//! [6]
//! [7]
void MainWindow::createHorizontalGroupBox()
{
horizontalGroupBox = new QGroupBox(tr("Horizontal layout"));
QHBoxLayout *layout = new QHBoxLayout;
for (int i = 0; i < NumButtons; ++i) {
buttons[i] = new QPushButton(tr("Button %1").arg(i + 1));
layout->addWidget(buttons[i]);
}
horizontalGroupBox->setLayout(layout);
}
//! [7]
//! [8]
void MainWindow::createGridGroupBox()
{
gridGroupBox = new QGroupBox(tr("Grid layout"));
//! [8]
QGridLayout *layout = new QGridLayout;
//! [9]
for (int i = 0; i < NumGridRows; ++i) {
labels[i] = new QLabel(tr("Line %1:").arg(i + 1));
lineEdits[i] = new QLineEdit;
layout->addWidget(labels[i], i + 1, 0);
layout->addWidget(lineEdits[i], i + 1, 1);
}
//! [9] //! [10]
smallEditor = new QTextEdit;
smallEditor->setPlainText(tr("This widget takes up about two thirds of the "
"grid layout."));
layout->addWidget(smallEditor, 0, 2, 4, 1);
//! [10]
//! [11]
layout->setColumnStretch(1, 10);
layout->setColumnStretch(2, 20);
gridGroupBox->setLayout(layout);
}
//! [11]
//! [12]
void MainWindow::createFormGroupBox()
{
formGroupBox = new QGroupBox(tr("Form layout"));
QFormLayout *layout = new QFormLayout;
layout->addRow(new QLabel(tr("Line 1:")), new QLineEdit);
layout->addRow(new QLabel(tr("Line 2, long text:")), new QComboBox);
layout->addRow(new QLabel(tr("Line 3:")), new QSpinBox);
formGroupBox->setLayout(layout);
}
MainWindow::~MainWindow()
{
delete ui;
}
二、垂直布局(QVBoxLayout)
QVBoxLayout:在垂直的方向上排列控件 上下排列
QVBoxLayout* pLayout = new QVBoxLayout();//垂直布局
QPushButton* p1 = new QPushButton("p1");
QPushButton* p2 = new QPushButton("p2");
QPushButton* p3 = new QPushButton("p3");
QPushButton* p4 = new QPushButton("p4");
pLayout->addWidget(p1);
pLayout->addWidget(p2);
pLayout->addWidget(p3);
pLayout->addWidget(p4);
this->setLayout(pLayout);
三、网格布局(QGridLayout)
- 格栅布局,也被称作网格布局(多行多列)。
- QGridLayout 类将控件放置到网格中布局,它本身会从父窗口或父布局中占据尽可能多的界面空间,然后把自己的空间划分为行和列,再把每个控件塞到设置好的一个或多个单元格中。
- 以下是func.h和widget.h
//func.h
#ifndef FUNC_H
#define FUNC_H
#include <iostream>
#include <stack>
#include <ctype.h>
#include <vector>
#include <string.h>
using namespace std;
int instack(string c);
int outstack(string c);
vector<string> InfixToPostfix(string str);
bool operation(string tmp,stack<double> &stk);
double postfix2ans(vector<string> exp);
void test();
#endif // FUNC_H
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QGridLayout>
#include <QVBoxLayout>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
/* 属性 */
private:
QPushButton *btnCalculator[24]; // 定义24个按键
QLineEdit *displayLineEdit; // 显示文本行
QLineEdit *displayExpressionLineEdit; // 显示表达式
QVBoxLayout *vLayout; // 垂直布局
QGridLayout *bottomLayout; // 格子布局
bool equalFlag; //
bool firstPressFlag; // 第一次按下标志位
/* 函数 */
private:
void initWidget(); // 初始化窗口
void BtnNumberOperator(QString num);// 数字按键操作
/* 信号 */
signals:
void SignalsrestartCalculator(); // 重新开始计算信号
/* 槽函数 */
private slots:
/* 按键点击槽函数 */
void SltBtnNumber0Clicked(); // 按键点击槽函数
void SltBtnNumber1Clicked(); // 按键点击槽函数
void SltBtnNumber2Clicked(); // 按键点击槽函数
void SltBtnNumber3Clicked(); // 按键点击槽函数
void SltBtnNumber4Clicked(); // 按键点击槽函数
void SltBtnNumber5Clicked(); // 按键点击槽函数
void SltBtnNumber6Clicked(); // 按键点击槽函数
void SltBtnNumber7Clicked(); // 按键点击槽函数
void SltBtnNumber8Clicked(); // 按键点击槽函数
void SltBtnNumber9Clicked(); // 按键点击槽函数
void SltBtnAddClicked(); // 加
void SltBtnMinusClicked(); // 减
void SltBtnMultiplyClicked(); //乘
void SltBtnDivideClicked(); // 除
void SltBtnPointClicked(); // 小数点
void SltBtnEqualClicked(); // 等于
void SltBtnBackSpaceClicked(); // 退格
void SltBtnCEClicked(); // CE
void SltBtnCClicked(); // C
void SltsrestartCalculator(); // 重新开始计算槽函数
};
#endif // WIDGET_H
- 以下是func.cpp
#include"func.h"
int instack(string c)//堆栈内部的运算符优先级
{
int priority;
if(c=="(")
priority=0;
if(c=="+"||c=="-")
priority=1;
if(c=="*"||c=="/")
priority=2;
if(c=="#")
priority=0;
return priority;
}
int outstack(string c)//堆栈外的运算符优先级
{
int priority;
if(c=="(")
priority=3;
if(c=="+"||c=="-")
priority=1;
if(c=="*"||c=="/")
priority=2;
return priority;
}
vector<string> InfixToPostfix(string str)
{
vector<string> exp,res;
string tstr="";
for(std::size_t i=0;i < str.length();i++)
{
//cout<<i<<endl;
if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='('||str[i]==')')
{
if(tstr.length()!=0)
{
exp.push_back(tstr);
tstr="";
}
tstr+=str[i];
exp.push_back(tstr);
tstr="";
}
else
{
tstr+=str[i];
}
}
if(tstr.length()!=0)
exp.push_back(tstr);
exp.push_back("#");
stack<string> stk;//存放 运算符和括号的栈
stk.push("#");
//string test="#";
string st="";
//cout<<exp.size()<<endl;
//int i=0;
for(std::size_t i=0;i<exp.size()-1;i++)//for(i=0,st=exp[i];exp[i]!="#";i++,st=exp[i])
{
st=exp[i];
if(st==")")
{
while(stk.top()!="(")
{
res.push_back(stk.top());
stk.pop();
}
stk.pop();
}
else if(st=="+"||st=="-"||st=="*"||st=="/"||st=="("||st=="#")
{
while(instack(stk.top())>=outstack(st))
{
res.push_back(stk.top());
stk.pop();
}
stk.push(st);
}
else
{
res.push_back(st);
}
}
while(!stk.empty())
{
if(stk.top()!="#")
{
res.push_back(stk.top());
}
stk.pop();
}
return res;
}
bool operation(string tmp,stack<double> &stk)
{
double a=0,b=0;//操作数
if(stk.size()<2)
{
cout<<"miss operator number"<<endl;
}
else
{
a=stk.top();
stk.pop();
b=stk.top();
stk.pop();
if(tmp=="+")
{
stk.push(b+a);
}
else if(tmp=="-")
{
stk.push(b-a);
}
else if(tmp=="*")
{
stk.push(b*a);
}
else if(tmp=="/")
{
if(a==0)
{
cout<<"denominator is 0!!!"<<endl;
return false;
}
else
{
stk.push(b/a);
}
}
}
return true;
}
double postfix2ans(vector<string> exp)
{
string tmp;//临时存放后缀表达式的每一项
bool flag=true;
stack<double> stk;
for(std::size_t i=0;i<exp.size();i++)
{
tmp=exp[i];
if(tmp=="+"||tmp=="-"||tmp=="*"||tmp=="/")
{
flag=operation(tmp,stk);
if(!flag)
return 0;
}
else
{
stk.push(atof(tmp.c_str()));//c_str是Borland封装的String类中的一个函数,它返回当前字符串的首字符地址。
}
}
return stk.top();
}
- 下面是计算器的 widget.cpp
#include "widget.h"
#include "func.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
initWidget(); // 初始化窗口
}
Widget::~Widget()
{
}
void Widget::initWidget()
{
this->setWindowTitle(tr("简易计算器")); //设置程序标题
this->setGeometry(0,0,800,480); //排版
/* 显示行 */
displayLineEdit = new QLineEdit(); //文本输入与显示
// displayLineEdit->resize(800,100); // 设置大小
displayLineEdit->setReadOnly(true); // 设置只读
displayLineEdit->setFont(QFont("黑体",20)); // 改变字体的大小,对话框也会变化
/* 显示表达式 */
displayExpressionLineEdit = new QLineEdit(); //文本输入与显示
displayExpressionLineEdit->setReadOnly(true); // 设置只读
displayExpressionLineEdit->setFont(QFont("黑体",16)); // 改变字体的大小,对话框也会变化
/* 按键 */
btnCalculator[0] = new QPushButton("%");
btnCalculator[1] = new QPushButton("CE");
btnCalculator[2] = new QPushButton("C");
btnCalculator[3] = new QPushButton("<-");
btnCalculator[4] = new QPushButton("");
btnCalculator[5] = new QPushButton("");
btnCalculator[6] = new QPushButton("");
btnCalculator[7] = new QPushButton("/");
btnCalculator[8] = new QPushButton("7");
btnCalculator[9] = new QPushButton("8");
btnCalculator[10] = new QPushButton("9");
btnCalculator[11] = new QPushButton("X");
btnCalculator[12] = new QPushButton("4");
btnCalculator[13] = new QPushButton("5");
btnCalculator[14] = new QPushButton("6");
btnCalculator[15] = new QPushButton("-");
btnCalculator[16] = new QPushButton("1");
btnCalculator[17] = new QPushButton("2");
btnCalculator[18] = new QPushButton("3");
btnCalculator[19] = new QPushButton("+");
btnCalculator[20] = new QPushButton("");
btnCalculator[21] = new QPushButton("0");
btnCalculator[22] = new QPushButton(".");
btnCalculator[23] = new QPushButton("=");
vLayout = new QVBoxLayout(this); // 创建主布局为垂直布局
bottomLayout = new QGridLayout(); // 为按键创建格子布局
/* 总体布局 */
vLayout->addWidget(displayExpressionLineEdit); // 添加文本区域到布局
vLayout->addWidget(displayLineEdit); // 添加文本区域到布局
vLayout->addLayout(bottomLayout); //addLayout向布局中添加子布局,addWidget:向布局中添加控件
/* 下面布局 按键格子布局 6*4 */
for(int i = 0; i< 6;i++){
for(int j = 0; j< 4;j++){
bottomLayout->addWidget(btnCalculator[i * 4 + j],i,j);
}
}
/* 按键点击槽函数 */
/* 数字按键 0-9 */
connect(btnCalculator[21],SIGNAL(clicked()),this,SLOT(SltBtnNumber0Clicked())); //按键连接
connect(btnCalculator[16],SIGNAL(clicked()),this,SLOT(SltBtnNumber1Clicked()));
connect(btnCalculator[17],SIGNAL(clicked()),this,SLOT(SltBtnNumber2Clicked()));
connect(btnCalculator[18],SIGNAL(clicked()),this,SLOT(SltBtnNumber3Clicked()));
connect(btnCalculator[12],SIGNAL(clicked()),this,SLOT(SltBtnNumber4Clicked()));
connect(btnCalculator[13],SIGNAL(clicked()),this,SLOT(SltBtnNumber5Clicked()));
connect(btnCalculator[14],SIGNAL(clicked()),this,SLOT(SltBtnNumber6Clicked()));
connect(btnCalculator[8],SIGNAL(clicked()),this,SLOT(SltBtnNumber7Clicked()));
connect(btnCalculator[9],SIGNAL(clicked()),this,SLOT(SltBtnNumber8Clicked()));
connect(btnCalculator[10],SIGNAL(clicked()),this,SLOT(SltBtnNumber9Clicked()));
/* 加减乘除 */
connect(btnCalculator[19],SIGNAL(clicked()),this,SLOT(SltBtnAddClicked())); // 加
connect(btnCalculator[15],SIGNAL(clicked()),this,SLOT(SltBtnMinusClicked()));// 减
connect(btnCalculator[11],SIGNAL(clicked()),this,SLOT(SltBtnMultiplyClicked())); // 乘
connect(btnCalculator[7],SIGNAL(clicked()),this,SLOT(SltBtnDivideClicked())); // 除
connect(btnCalculator[22],SIGNAL(clicked()),this,SLOT(SltBtnPointClicked())); // 小数点
connect(btnCalculator[23],SIGNAL(clicked()),this,SLOT(SltBtnEqualClicked())); // 等于
connect(btnCalculator[3],SIGNAL(clicked()),this,SLOT(SltBtnBackSpaceClicked())); // 退格
connect(btnCalculator[1],SIGNAL(clicked()),this,SLOT(SltBtnCEClicked())); // CE键 清除最后输入的一个数字
connect(btnCalculator[2],SIGNAL(clicked()),this,SLOT(SltBtnCClicked())); // C键 清除全部
/* 重新开始计算槽函数 */
connect(this,SIGNAL(SignalsrestartCalculator()),this,SLOT(SltsrestartCalculator()));
SltsrestartCalculator(); // 重新开始计算
}
/**
* Widget::SltBtnNumber0Clicked
* 按键0
*/
void Widget::SltBtnNumber0Clicked()
{
BtnNumberOperator("0");
}
void Widget::SltBtnNumber1Clicked()
{
BtnNumberOperator("1");
}
void Widget::SltBtnNumber2Clicked()
{
BtnNumberOperator("2");
}
void Widget::SltBtnNumber3Clicked()
{
BtnNumberOperator("3");
}
void Widget::SltBtnNumber4Clicked()
{
BtnNumberOperator("4");
}
void Widget::SltBtnNumber5Clicked()
{
BtnNumberOperator("5");
}
void Widget::SltBtnNumber6Clicked()
{
BtnNumberOperator("6");
}
void Widget::SltBtnNumber7Clicked()
{
BtnNumberOperator("7");
}
void Widget::SltBtnNumber8Clicked()
{
BtnNumberOperator("8");
}
void Widget::SltBtnNumber9Clicked()
{
BtnNumberOperator("9");
}
/**
* Widget::SltBtnAddClicked
* + 运算符
*/
void Widget::SltBtnAddClicked()
{
firstPressFlag = false; // 不是第一次按下
equalFlag = false; // 等号被打断
/* 判断符号重复 */
// 截取最后一个字符
QString operatorSignal = "+-*/.="; // 一些操作运算符
QString laststr = displayLineEdit->text().right(1);
// qDebug() << laststr << endl;
/* 判断最后一个字符是不是不是下面这些符号 */
bool iscontains = operatorSignal.contains(laststr,Qt::CaseSensitive); // 大小写敏感
if(!iscontains){ // 包含 啥也不管
displayLineEdit->setAlignment(Qt::AlignLeft); // 左对齐
displayLineEdit->setText(displayLineEdit->text()+="+");
}
}
void Widget::SltBtnMinusClicked()
{
firstPressFlag = false; // 不是第一次按下
equalFlag = false; // 等号被打断
/* 判断符号重复 */
// 截取最后一个字符
QString operatorSignal = "+-*/.="; // 一些操作运算符
QString laststr = displayLineEdit->text().right(1);
// qDebug() << laststr << endl;
/* 判断最后一个字符是不是不是下面这些符号 */
bool iscontains = operatorSignal.contains(laststr,Qt::CaseSensitive); // 大小写敏感
if(!iscontains){ // 包含 啥也不管
displayLineEdit->setAlignment(Qt::AlignLeft); // 左对齐
displayLineEdit->setText(displayLineEdit->text()+="-");
}
}
void Widget::SltBtnMultiplyClicked()
{
firstPressFlag = false; // 不是第一次按下
equalFlag = false; // 等号被打断
/* 判断符号重复 */
// 截取最后一个字符
QString operatorSignal = "+-*/.="; // 一些操作运算符
QString laststr = displayLineEdit->text().right(1);
// qDebug() << laststr << endl;
/* 判断最后一个字符是不是不是下面这些符号 */
bool iscontains = operatorSignal.contains(laststr,Qt::CaseSensitive); // 大小写敏感
if(!iscontains){ // 包含 啥也不管
displayLineEdit->setAlignment(Qt::AlignLeft); // 左对齐
displayLineEdit->setText(displayLineEdit->text()+="*");
}
}
void Widget::SltBtnDivideClicked()
{
firstPressFlag = false; // 不是第一次按下
equalFlag = false; // 等号被打断
/* 判断符号重复 */
// 截取最后一个字符
QString operatorSignal = "+-*/.="; // 一些操作运算符
QString laststr = displayLineEdit->text().right(1);
// qDebug() << laststr << endl;
/* 判断最后一个字符是不是不是下面这些符号 */
bool iscontains = operatorSignal.contains(laststr,Qt::CaseSensitive); // 大小写敏感
if(!iscontains){ // 包含 啥也不管
displayLineEdit->setAlignment(Qt::AlignLeft); // 左对齐
displayLineEdit->setText(displayLineEdit->text()+="/");
}
}
void Widget::SltBtnPointClicked()
{
firstPressFlag = false; // 不是第一次按下
equalFlag = false; // 等号被打断
/* 判断符号重复 */
// 截取最后一个字符
QString operatorSignal = "+-*/.="; // 一些操作运算符
QString laststr = displayLineEdit->text().right(1);
// qDebug() << laststr << endl;
/* 判断最后一个字符是不是不是下面这些符号 */
bool iscontains = operatorSignal.contains(laststr,Qt::CaseSensitive); // 大小写敏感
if(!iscontains){ // 包含 啥也不管
displayLineEdit->setAlignment(Qt::AlignLeft); // 左对齐
displayLineEdit->setText(displayLineEdit->text()+=".");
}
}
/**
* Widget::SltBtnEqualClicked
* = 运算符 获取表达式 计算结果
*/
void Widget::SltBtnEqualClicked()
{
firstPressFlag = false; // 不是第一次按下
equalFlag = true; // 等号按下
/* 剔除最后一个字符不是数字的情况 */
// 截取最后一个字符
QString operatorSignal = "+-*/.="; // 一些操作运算符
QString laststr = displayLineEdit->text().right(1);
QString str = displayLineEdit->text(); // 获取表达式
// qDebug() << laststr << endl;
/* 判断最后一个字符是不是不是下面这些符号 */ //contains:包含
bool iscontains = operatorSignal.contains(laststr,Qt::CaseSensitive); // 大小写敏感 CaseSensitive:区分大小写
if(iscontains){ // 包含 剔除最后一个字符
str = str.left(str.length() -1); // 删除最后一个字符
}
// 如果不包含直接计算下面的
// 计算结果
displayLineEdit->setAlignment(Qt::AlignRight); // 靠右对齐
displayExpressionLineEdit->setAlignment(Qt::AlignRight); // 靠右对齐
displayLineEdit->setText(str += "="); // 表达式加上等号
QString res = displayLineEdit->text(); // 获取表达式
string s = res.toStdString(); // Qt 转化为 c++ 使用的字符串
double ans = postfix2ans(InfixToPostfix(s)); // 计算结果
displayExpressionLineEdit->setText(displayLineEdit->text()); // 显示表达式
displayLineEdit->setText(QString::number(ans)); // 显示结果
}
/**
* Widget::SltBtnBackSpaceClicked
* 退格键 去掉最后一个字符
*/
void Widget::SltBtnBackSpaceClicked()
{
QString res = displayLineEdit->text(); // 获取表达式
/* 删除最后一个字符 */
res = res.left(res.length() - 1); // 去掉最后一个字符
displayLineEdit->setText(res); // 显示在文本行中
}
/**
* Widget::SltBtnCEClicked
* CE键 删除掉最后输入的数字
*/
void Widget::SltBtnCEClicked()
{
QString operatorSignal = "+-*/.="; // 一些操作运算符
QString numberSignal = "0123456789"; // 数字
QString str = displayLineEdit->text(); // 获取表达式
int index = 0; // 记录删除数字的个数
/* 333 333+ 333+333 */
while(1){
/* 判断 字符串是否为空 或者是 333这种纯数字 后面也会为空的情况 */
if(str == ""){
displayLineEdit->setText("0");
firstPressFlag = true; // 第一次按下
break;
}
QString laststr = str.right(1); // 截取最后一个字符
qDebug() << laststr <<endl;
/* 判断最后一个字符是不是数字 */
if(numberSignal.contains(laststr,Qt::CaseSensitive)){ // 是数字 操作
str = str.left(str.length() -1); // 删除最后一个字符
index ++;
}else{ // 不是数字 那就是表达式 退出
displayLineEdit->setText(displayLineEdit->text().left(displayLineEdit->text().length() - index));
break;
}
}
}
/**
* Widget::SltBtnCClicked
* C键 清除全部
*/
void Widget::SltBtnCClicked()
{
SltsrestartCalculator(); // 重新开始计算
}
/**
* BtnNumberOperator
* 数字按键操作 相同的操作 封装一个函数
*/
void Widget::BtnNumberOperator(QString num)
{
if(equalFlag)// 如果上一个是等号 按下数字就是重新开始
emit SignalsrestartCalculator(); // 发出信号
if(firstPressFlag){ // 如果是第一次按下 需要先清除数字0 也就是直接显示这个数字 否则加上这个数字
firstPressFlag = false;
displayLineEdit->setText(num); // 显示num
}
else
displayLineEdit->setText(displayLineEdit->text()+= num); // 显示的文字加上num
}
/**
* Widget::SltsrestartCalculator
* 重新开始计算槽函数
*/
void Widget::SltsrestartCalculator()
{
firstPressFlag = true; // 第一次按下
equalFlag = false; // 等号被打断
displayLineEdit->clear(); // 清空
displayExpressionLineEdit->clear(); // 清空
displayLineEdit->setText("0"); // 默认状态显示一个0
displayLineEdit->setAlignment(Qt::AlignLeft); // 左对齐
}
- 以下是main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
总结
上面做的是一个计算器的程序;很好的展现了网格布局和垂直布局,是一个很好的例子,大家可以看看。