QT自定义优雅的表单控件,简单实现设置界面布局

QT自定义优雅的表单控件,简单实现设置界面布局

一、实现效果

在这里插入图片描述

表单工具类FormView

FormView.h

#pragma once
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QStyleOption>
#include <QPainter>
#include <QApplication>
#include <QScreen>
#include <QCheckBox>
#include "QString"
#include "QMap"
#include <functional>
class FormView : public QWidget
{
	Q_OBJECT
public:
	//指定大小的表单,用于纯代码编写UI
	FormView(int width, int height, QWidget* parent = nullptr);
	//不指定大小的表单,用于在designer中使用
	FormView(QWidget* parent = nullptr);
	~FormView();
	//在表单中插入一个控件
	void addWidgetToForm(QWidget* widget);
	//在表单中插入一个可填写项
	void addEditableItem(QString title, QString place_holder);
	//在表单中插入一个可勾选项
	void addCheckableItem(QString title, QString content, bool init_status, std::function<void(bool)> call_back);
	//设置表单控件的可用性
	void setItemEnabled(QString item_title, bool enabled);
	//获取具体控件的句柄
	QLineEdit* getEditableItem(QString title);
	QCheckBox* getCheckableItem(QString title);
	//在表单头部添加一个弹簧(使表单靠下)
	void startForm();
	//在表单尾部添加一个弹簧(使表单靠上)
	void endForm();
	//start end 同时使用,表单居中

	//清空表单所有可填写项
	void Clear();
protected:
	void Init(int width, int height);
	void Init();
	void paintEvent(QPaintEvent* event) override;
private:
	QVBoxLayout* mainLayout;
	QMap<QString, QWidget*> editItems;
	QMap<QString, QWidget*> checkItems;
};

FormView.cpp

#include "FormView.h"
FormView::FormView(int width, int height, QWidget* parent) : QWidget(parent)
{
	Init(width, height);
}

FormView::FormView(QWidget* parent /*= nullptr*/) : QWidget(parent)
{
	Init();
}

FormView::~FormView()
{

}

void FormView::Clear()
{
	for(auto widget : editItems)
	{
		QLineEdit* l = widget->findChild<QLineEdit*>();
		if (l != nullptr)l->clear();
	}
}

void FormView::Init(int width, int height)
{
	setFixedSize(width, height);
	Init();
}

void FormView::Init()
{
	setObjectName(QStringLiteral("form_view"));
	setStyleSheet(QStringLiteral("QWidget#form_view{border:none;background-color:white;border-top-right-radius:8px;border-bottom-right-radius:8px;}"));
	mainLayout = new QVBoxLayout(this);
}

void FormView::paintEvent(QPaintEvent* event)
{
	QStyleOption opt;
	opt.init(this);
	QPainter p(this);
	style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
	QWidget::paintEvent(event);
	
}

void FormView::addWidgetToForm(QWidget* widget)
{
	mainLayout->addSpacing(10);
	mainLayout->addWidget(widget, 0, Qt::AlignLeft);
}

void FormView::addEditableItem(QString title, QString place_holder)
{
	int height = 30;//调整输入框大小
	QWidget* formItem = new QWidget;
	formItem->setFixedSize(width() * 0.8, height+10);
	QHBoxLayout* layout = new QHBoxLayout(formItem);
	QLabel* label = new QLabel(title);
	label->setStyleSheet(QStringLiteral("QLabel{font-size:16px;font-family:Microsoft Yahei;color:#000000;}"
		"QLabel:disabled{font-size:16px;font-family:Microsoft Yahei;color:#828488;}"));
	QLineEdit* edit = new QLineEdit(this);
	edit->setPlaceholderText(place_holder);
	edit->setFixedSize(width() * 0.5, height);
	edit->setStyleSheet(QStringLiteral("QLineEdit{padding-left:22px;padding-right:22px;font-size:15px;font-family:Microsoft Yahei;border-radius:3px;border:1px solid #dcdfe6;color:#606266;}"
		"QLineEdit:hover{border:1px solid #909399;}"
		"QLineEdit:focus{border:1px solid #409EFF;}"));
	edit->setFocusPolicy(Qt::FocusPolicy::ClickFocus);

	layout->addWidget(label, 0, Qt::AlignLeft);
	layout->addStretch();
	layout->addWidget(edit, 0, Qt::AlignRight);

	editItems.insert(title, formItem);
	addWidgetToForm(formItem);
}

void FormView::addCheckableItem(QString title, QString content, bool init_status, std::function<void(bool)> call_back)
{
	int height = 30;
	QWidget* formItem = new QWidget;
	formItem->setFixedSize(width() * 1, height+10);
	QHBoxLayout* layout = new QHBoxLayout(formItem);
	QLabel* label = new QLabel(content);
	label->setStyleSheet(QStringLiteral("QLabel{font-size:16px;font-family:Microsoft Yahei;color:#000000;}"
		"QLabel:disabled{font-size:16px;font-family:Microsoft Yahei;color:#828488;}"));
	QCheckBox* check = new QCheckBox();
	check->setStyleSheet(QStringLiteral("QCheckBox{font-size:16px;font-family:Microsoft Yahei;border:none;}"
		"QCheckBox::indicator{width:20px;height:20px;border-radius:4px;border:1px solid #dcdfe6;}"
		"QCheckBox::indicator:hover{border-radius:4px;border:2px solid #409EFF;}"
		"QCheckBox::indicator:checked{border-radius:4px;border:1px solid #409EFF;background-color:#409EFF;image:url(./icons/checked.png);}"
		"QCheckBox::indicator:disabled{background-color:#C2C2C2;image:url(./icons/disable.png);}"));
	check->setChecked(init_status);

	layout->addWidget(check, 0, Qt::AlignLeft);
	layout->addWidget(label, 0, Qt::AlignLeft);
	layout->addStretch();

	connect(check, &QCheckBox::stateChanged, this, [=]() {
		call_back(check->isChecked());
		});

	checkItems.insert(title, formItem);
	addWidgetToForm(formItem);
}

void FormView::setItemEnabled(QString item_title, bool enabled)
{
	QWidget* w = editItems.value(item_title);
	if (w != nullptr)w->setEnabled(enabled);

	QWidget* w2 = checkItems.value(item_title);
	if (w2 != nullptr)w2->setEnabled(enabled);
}

QLineEdit* FormView::getEditableItem(QString title)
{
	QWidget* w = editItems.value(title);
	if (w == nullptr)return nullptr;
	return w->findChild<QLineEdit*>();
}

QCheckBox* FormView::getCheckableItem(QString title)
{
	QWidget* w = checkItems.value(title);
	if (w == nullptr)return nullptr;
	return w->findChild<QCheckBox*>();
}

void FormView::startForm()
{
	if (mainLayout == nullptr)mainLayout = new QVBoxLayout(this);
	mainLayout->addStretch();
}

void FormView::endForm()
{
	mainLayout->addStretch();
}

核心函数

函数变量功能
addEditableItemtitle: 输入框前面的提示文字,同时作为该控件的标识符
place_holder: 输入框中的提示文字
在表单中插入一个可填写项
addCheckableItemtitle: 不显示在UI中,仅作为该控件的标识符
content: 勾选框后面的内容
init_status: 勾选框的初始状态
call_back: 勾选状态变化后的回调函数
在表单中插入一个可勾选项

三、使用方法

1、纯代码使用

新建一个UITest类作为窗体,部分代码如下:

UITest::UITest(QWidget *parent)
	: QMainWindow(parent)
{
	Init();
	//ui.setupUi(this);
}

UITest::~UITest()
{}

void UITest::Init()
{
	int nScreenWidth = QApplication::primaryScreen()->geometry().width();
	int nScreenHeight = QApplication::primaryScreen()->geometry().height();
	setFixedSize(nScreenWidth * 0.8, nScreenHeight * 0.8);
	FormView* form = new FormView(nScreenWidth*0.2,nScreenHeight * 0.4,this);
}

然后再main函数中使其显示即可:

	UITest t;
	t.show();

2、在designer中使用

新建一个qt widget类,在UI中添加Widget控件并提升为FormView:
在这里插入图片描述
需要注意的是,本表单工具仅能排成一列,若需要多列则应如图中所示设计多个表单控件。

3、添加表格内容

为避免表格内项目大小出错,建议在paintEvent中初始化表格:

void SettingsView::paintEvent(QPaintEvent* event)
{
	QWidget::paintEvent(event);
	if (!isInited)
	{
		InitUI();
	}
	
}
void SettingsView::InitUI()
{
	QSize size(40, 40);
	QPixmap mipmap_setting("./icons/setting_icon.png");
	ui.setting_icon->setPixmap(mipmap_setting.scaled(size));
	ui.btn_setting_confirm->setText(QStringLiteral("确认"));


	//left form
	//ui.settings_left->startForm();
	ui.settings_left->addEditableItem(QStringLiteral("参考站IP"), QStringLiteral("127.0.0.1"));
	ui.settings_left->addEditableItem(QStringLiteral("参考站端口"), QStringLiteral("8080"));
	ui.settings_left->addEditableItem(QStringLiteral("流动站IP"), QStringLiteral("127.0.0.1"));
	ui.settings_left->addEditableItem(QStringLiteral("流动站端口"), QStringLiteral("8080"));
	ui.settings_left->addEditableItem(QStringLiteral("卫星系统"), QStringLiteral("B&C&G&E"));
	ui.settings_left->addCheckableItem(QStringLiteral("偏差模式"), QStringLiteral("定位结果以偏差形式显示"), true,[=](bool ischecked) {
		ui.settings_left->setItemEnabled(QStringLiteral("流动站坐标X"), ischecked);
		ui.settings_left->setItemEnabled(QStringLiteral("流动站坐标Y"), ischecked);
		ui.settings_left->setItemEnabled(QStringLiteral("流动站坐标Z"), ischecked);
	});
	ui.settings_left->addEditableItem(QStringLiteral("流动站坐标X"), QStringLiteral("地心坐标系X轴"));
	ui.settings_left->addEditableItem(QStringLiteral("流动站坐标Y"), QStringLiteral("地心坐标系Y轴"));
	ui.settings_left->addEditableItem(QStringLiteral("流动站坐标Z"), QStringLiteral("地心坐标系Z轴"));
	ui.settings_left->endForm();

	//right form

	isInited = true;
	//fill forms
	fillForms();

}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值