1. 重点内容
- 解释bean是什么。
- 如何得到一个模块的BeanConfig及Bean。
- 一个模块的BeanConfig及Bean是如何销毁。
2. 运行展示
3. 程序示例
3.1 什么是bean
模块化是我们构建复杂系统的一种简单方法,它是复杂的东西抽象成可以理解的简单化的具体体现,bean就是想通过将各种系统所需要的东西通过抽象组合成简单的模块,bean模块管理模块化的东西,bean它可以是抽象的任何有用的东西,在peanutlib中抽象的bean模块就有application模块,bean模块,db模块,xml模块,json模块,log模块等,每个模块即独立完成自己应该做的事情,又可以协作完成更加复杂的事情。
我们知道对象的分工协作构成了一个模块,在定义一个模块时,将模块看成BeanConfig,将对象看成Bean,我们将整个系统看成是BeanConfig与Bean的集合。我们通过下图来举一个例子,下图我们将整体看一个系统,该系统有3个模块,分别是A模块(bean1,bean2,bean3 对象),B模块(bean1,bean2 对象),C模块(bean1,bean2 对象),每个模块用beanConfig来表示。
peanut_appconfig.xml配置文件是专门用来配置peanutlib的BeanConfig与Bean,下面是一个日志模块的例子。
<beanConfig chooseBeanId="logBeanQtlog" className="peanut::PlLogBeanConfig" id="logBeanConfigSample" name="LogModule" type="Log">
<bean isDebug="true" className="peanut::PlQtLogController" isWarn="true" id="logBean_1" name="" isSendSingal="true" isLogForm="false" isError="true" isConversionPattern="true" isFatal="true" isInfo="true" type="QLog"/>
<bean className="peanut::PlLog4qtController" id="logBean_2" filePath="./config/log4qt.conf" name="" isSendSingal="true" isLogForm="false" isConversionPattern="true" type="Log4qt"/>
</beanConfig>
- beanConfig标签(logBeanConfigSample):日志模块的BeanConfig。
id:日志模块的唯一标识。
name:模块名称。
className: log模块的BeanConfig的类名
type:模块类型。
- bean标签(logBean_1):日志模块的bean,它对应的是peanut::PlQtLogController对象,该对象是用QLog日志输出框架。 另外在bean标签中定义该对象的初始属性及值。
- bean标签(logBean_2):日志模块的bean,它对应的是peanut::PlLog4qtController对象,该对象是用log4qt日志输出框架。 另外在bean标签中定义该对象的初始属性及值。
3.2 如何得到一个模块的BeanConfig及Bean
通常模块BeanConfig与Bean是已设计并实现,如果要得到一个已实现的BeanConfig与Bean,来为正在编辑的代码服务,在程序中如何实现?
下在我们通过一个例子来说明,这个例子是使用日志模块,从BeanConfig中得到它对应的日志模块及该模块对应的Bean,用Bean产生两种不同日志框架的输出。
首先我们用00u的项目工程代码“pssample00u0”来创建一个项目的基本环境,当然我们不能直接用pssample00u0来创建,要新创建一个工程代码“pssample01u0”,再将pssample00u0的程序及程序资源复制到当前目录中。
- 修改pssample00u0.pro文件
#生成目标
CONFIG(release, debug|release) {
#realease模式下的目标文件
TARGET = psample01u0
} else {
#debug模式下的目标文件
TARGET = psample01u0d
}
注:将生成目标改成pssample01u0
- 新建“PsBean00MainWindow”窗口,演示如何使用日志模块
在peanut_appconfig.xml文件中一个标签beanConfig,该标签描述的日志模块
<beanConfig chooseBeanId="logBeanQtlog" className="peanut::PlLogBeanConfig" id="logBeanConfigSample" name="LogModule" type="Log">
<bean isDebug="true" className="peanut::PlQtLogController" isWarn="true" id="logBean_1" name="" isSendSingal="true" isLogForm="false" isError="true" isConversionPattern="true" isFatal="true" isInfo="true" type="QLog"/>
<bean className="peanut::PlLog4qtController" id="logBean_2" filePath="./config/log4qt.conf" name="" isSendSingal="true" isLogForm="false" isConversionPattern="true" type="Log4qt"/>
</beanConfig>
下面是我们通过日志模块的配置项,来使用该模块的服务。
- 头文件ps_bean00_mainwindow.h
/***************************************************************************
* This file is part of the Peanut Library project *
* Copyright (C) 2022 by Wang Ren Qian *
* author:积木虎 154318869@qq.com *
* Peanut Software Studio *
****************************************************************************/
#ifndef PS_BEAN00_MAINWINDOW_H
#define PS_BEAN00_MAINWINDOW_H
#include <QMainWindow>
#include <QTextCharFormat>
namespace peanut {
namespace Ui {
class PsBean00MainWindow;
}
class PsBean00MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit PsBean00MainWindow(QWidget *parent = nullptr);
~PsBean00MainWindow();
enum LogTypeFlag {
debug = 0x1,
info = 0x2,
warn = 0x3,
error = 0x4,
fatal = 0x5
};
Q_DECLARE_FLAGS(LogTypeFlags, LogTypeFlag)
private slots:
void on_btnLogBean1_clicked();
void on_btnLogBean2_clicked();
//输出日志到界面
void writeLog(const QString &logText, int flag);
private:
Ui::PsBean00MainWindow *ui;
int m_logRowCount=0; //行数
QTextCharFormat m_debugTextFormat;
QTextCharFormat m_infoTextFormat;
QTextCharFormat m_warnTextFormat;
QTextCharFormat m_errorTextFormat;
QTextCharFormat m_fatalTextFormat;
};
}
#endif // PS_BEAN00_MAINWINDOW_H
- 程序文件ps_bean00_mainwindow.cpp
/***************************************************************************
* This file is part of the Peanut Library project *
* Copyright (C) 2022 by Wang Ren Qian *
* author:积木虎 154318869@qq.com *
* Peanut Software Studio *
****************************************************************************/
#include "ps_application.h"
#include "ps_bean00_mainwindow.h"
#include "ui_ps_bean00_mainwindow.h"
#include <pl_log.h>
namespace peanut {
PsBean00MainWindow::PsBean00MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::PsBean00MainWindow)
{
ui->setupUi(this);
ui->plainTextEdit->setReadOnly(true);
m_debugTextFormat.setForeground(QBrush(Qt::black));
m_infoTextFormat.setForeground(QBrush(Qt::blue));
m_warnTextFormat.setForeground(QBrush(Qt::darkRed));
m_errorTextFormat.setForeground(QBrush(Qt::red));
m_fatalTextFormat.setForeground(QBrush(Qt::gray));
}
PsBean00MainWindow::~PsBean00MainWindow()
{
delete ui;
}
void peanut::PsBean00MainWindow::on_btnLogBean1_clicked()
{
//QLog日志框架
PlQtLogController *log = nullptr;
//得到app对象
PsApplication *app = PsApplication::getPsApplication();
try{
//从app对象得到BeanConfig
//参数1:logBeanConfigSample,对应peanut_appconfig.xml中beanConfig的id
//参数2:logBean_1,对应peanut_appconfig.xml中beanConfig的id=logBeanConfigSample,从属bean的id=logBean_1
QObject *obj = app->getBean("logBeanConfigSample", "logBean_1");
if(obj!=nullptr) {
//将obj对象转换成PlQtLogController对象
log = qobject_cast<PlQtLogController*>(obj);
}
else {
throw PeanutError(QObject::tr("PS示例模块异常:%1").arg(app->getError()));
}
if(log!=nullptr) {
QString logText = tr("[logBean_1]-[INFO日志]-当前设备001号运行状态正常...");
log->info(logText); //输出到控件台
writeLog(logText, info); //输出到界面
logText = tr("[logBean_1]-[DEBUG日志]-当前设备001号运行状态正常...");
log->info(logText); //输出到控件台
writeLog(logText, debug); //输出到界面
logText = tr("[logBean_1]-[WARN日志]-当前设备003号运行状态异常,无法连接该设备...");
log->warn(logText); //输出到控件台
writeLog(logText, warn); //输出到界面
logText = tr("[logBean_1]-[INFO日志]-当前设备005号运行状态错误,未启动A控制器...");
log->error(logText); //输出到控件台
writeLog(logText, error); //输出到界面
logText = tr("[logBean_1]-[FATAl日志]-当前设备008号运行状态已严重错误,导致所有设备运行停止...");
//log->fatal(logText); //输出到控件台
writeLog(logText, fatal); //输出到界面
}
} catch(PeanutError err) {
//如果异常,输出到系统运行日志
LOG_ERROR(PlBaseApplication::getGlobalLogger(), err.what());
PlMessageBox::warning(this, tr("异常警告信息"), err.what());
}
}
void peanut::PsBean00MainWindow::on_btnLogBean2_clicked()
{
//Log4qt日志框架
PlLog4qtController *log = nullptr;
//得到app对象
PsApplication *app = PsApplication::getPsApplication();
try{
//从app对象得到BeanConfig
//参数1:logBeanConfigSample,对应peanut_appconfig.xml中beanConfig的id
//参数2:logBean_2,对应peanut_appconfig.xml中beanConfig的id=logBeanConfigSample,从属bean的id=logBean_2
QObject *obj = app->getBean("logBeanConfigSample", "logBean_2");
if(obj!=nullptr) {
//将obj对象转换成PlQtLogController对象
log = qobject_cast<PlLog4qtController*>(obj);
}
else {
throw PeanutError(QObject::tr("PS示例模块异常:%1").arg(app->getError()));
}
if(log!=nullptr) {
QString logText = tr("[logBean_2]-[INFO日志]-当前设备003号运行状态正常...");
log->info(logText); //输出到控件台
writeLog(logText, info); //输出到界面
logText = tr("[logBean_2]-[DEBUG日志]-当前设备005号运行状态正常...");
log->info(logText); //输出到控件台
writeLog(logText, debug); //输出到界面
logText = tr("[logBean_2]-[WARN日志]-当前设备007号运行状态异常,无法连接该设备...");
log->warn(logText); //输出到控件台
writeLog(logText, warn); //输出到界面
logText = tr("[logBean_2]-[INFO日志]-当前设备002号运行状态错误,未启动A控制器...");
log->error(logText); //输出到控件台
writeLog(logText, error); //输出到界面
logText = tr("[logBean_2]-[FATAl日志]-当前设备009号运行状态已严重错误,导致所有设备运行停止...");
//log->fatal(logText); //输出到控件台
writeLog(logText, fatal); //输出到界面
}
} catch(PeanutError err) {
//如果异常,输出到系统运行日志
LOG_ERROR(PlBaseApplication::getGlobalLogger(), err.what());
PlMessageBox::warning(this, tr("异常警告信息"), err.what());
}
}
void PsBean00MainWindow::writeLog(const QString &logText, int flag)
{
if(flag == LogTypeFlag::debug) {
ui->plainTextEdit->mergeCurrentCharFormat(m_debugTextFormat);
}
if(flag == LogTypeFlag::info) {
ui->plainTextEdit->mergeCurrentCharFormat(m_infoTextFormat);
}
if(flag == LogTypeFlag::warn) {
ui->plainTextEdit->mergeCurrentCharFormat(m_warnTextFormat);
}
if(flag == LogTypeFlag::error) {
ui->plainTextEdit->mergeCurrentCharFormat(m_errorTextFormat);
}
if(flag == LogTypeFlag::fatal) {
ui->plainTextEdit->mergeCurrentCharFormat(m_fatalTextFormat);
}
ui->plainTextEdit->appendPlainText(QString("[%1]-").arg(++m_logRowCount) + logText);
}
}
- 设计UI文件ps_bean00_mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>peanut::PsBean00MainWindow</class>
<widget class="QMainWindow" name="peanut::PsBean00MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>bean示例-使用bean</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnLogBean1">
<property name="text">
<string>bean:logBean_1操作</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnLogBean2">
<property name="text">
<string>bean:logBean_2操作</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
- 将PsBean00MainWindow窗口挂到主窗口ps_mainwindow中
修改ps_mainwindow.cpp中的on_trigrMenu方法
void PsMainWindow::on_trigerMenu(QAction *action)
{
PsApplication *app = PsApplication::getPsApplication();
if(action != nullptr) {
QIcon icon;
int cur;
//得到菜单ui->menubar当前响应的单击的action对象,并得到它的对象名称
QString actName = action->objectName();
if(actName=="act_PlLogForm") { //识别是act_PlLogForm对象
if(this->m_logForm==nullptr) {
m_logForm = app->getGlobalLogForm();
}
icon = m_logForm->windowIcon();
if(icon.isNull()) { //如果m_logForm对象的图标为空
cur = ui->tabWidget->addTab(m_logForm, m_logForm->windowTitle());
}
else {
//增加m_logForm对象到Tab页中
cur = ui->tabWidget->addTab(m_logForm, icon, m_logForm->windowTitle());
}
m_logForm->show();
ui->tabWidget->setCurrentIndex(cur); //设置TabWidget的当前页
ui->tabWidget->setVisible(true);
}
else if(actName=="act_PsBean00MainWindow") {
PsBean00MainWindow *widget = new PsBean00MainWindow(this);
icon = widget->windowIcon();
widget->setAttribute(Qt::WA_DeleteOnClose); //关闭时自动删除
if(icon.isNull()) {
cur = ui->tabWidget->addTab(widget, widget->windowTitle());
}
else {
cur = ui->tabWidget->addTab(widget, icon, widget->windowTitle());
}
ui->tabWidget->setCurrentIndex(cur);
ui->tabWidget->setVisible(true);
}
}
}
4. 代码下载
代码下载链接:https://pan.baidu.com/s/12Qy7q6kHsu6q2MIi1errxQ
Peanutlib项目演示程序下载:peanut_pwdis: pwdis是QT应用系统开发框架(C++),采用分层模块化设计,底层peanutlib按模块封装方便易用的类库及API(xml,db,appconfig,log,grid,json,bean等十几个),应用层提供部门人员权限及报表等,还提供了开发中常用的组件使用。