当前位置:文档之家› QT C++图形界面编程技术

QT C++图形界面编程技术

QT C++图形界面编程技术
QT C++图形界面编程技术

通识教育课程论文

课程名称:C++图形界面编程技术_

学院_

专业班级

学号

姓名爱尔兰(KEN

联系方式irelandken@https://www.doczj.com/doc/6711204691.html,

任课教师LZ

论QT的信号/槽机制

——WindowCut—一个简单实用的截图软件在图形界面编程技术,我比较喜欢QT这个框架,喜欢它的一次编写,到处编译这种方式,既高效,移植性又强,我试过在window下用Qt creator开发一个软件,然后直接将工程放到linuxubunto 11.04下,再次用Qt creator打开之前的工程,很简单地直接编译一次,一个代码也不用改,就将该软件移植到Linux下了,这一点很不错。。。

更重要的是,Qt为我们带来了全新的思想:将一个工程逻辑分解为多个组件,利用强大的信号/槽机制,竟然可使这个工程分解为相互独立,互不干扰的若干个部分。以下,我将通过介绍我的WindowCut截图软件的编写过程来分析这种思想。

界面:

截图过程:

截图后的效果:

思想:

这个软件由1:主窗口mainWindow,2:全屏截图器FullEditFEdit(就是半透明的全屏的组件)和 3:截图查看器PicSeePSee组成,这3部分都是互相独立的类,在类的定义中,类与类之间无直接的函数调用,这些组件定义了

若干个signal/slot,而这3个类的实例是通过 signal/slot机制偶合在一

起的。

mainWindow上的Cut按键被按下后,mainWindow就隐藏,并发出一个StartCut()的信号,表示“开始截图”。。然后FEdit接收到StartCut()

信号后,它就初始化,并记录下此时刻的屏幕背景,最后全屏显示半透明的背景。。。然PSee接收这个信号后,它就隐藏起来。。

当用户在全屏截图器FEdit的全屏半透明背景上选定好区域后,FullEdit 就会隐藏窗口并发出FinishCut“截图完成”的信号(信号中包含了截图的地址),然后截图查看器PSee接收到FinishCut信号及其中的截图的地址后,就

会显示窗口,并在窗口上面绘制截图显示给用户,而mainWindow收到FinishCut信号后,就会显示主窗口,并使save按钮可见。

此后,用户点击save按钮并成功保存后,mainWindow就会发出PicSaved

“图片保存信号”,然后PSee会收到此信号,然后隐藏。

大概的流程就是这样。

软件的功能是简单的,但是,里面的思想却很有意义的。

对于mainWindow,它只管发射信号,压根儿不用知道有多少个对象收到这些信号(当然也不可能知道),并且当收到特定的信号时,就去执行信号处理器slot就可以了,FullEdit和PicSee也一样。。因为具体哪个信号与哪个槽有连接关系,不是在类的定义在确定的,而且信号/槽的连接是面向类的实例的(所以不可能由类的抽象或定义来确定),QObject::connect (sender, SIGNAL,receiver,SLOT)这个函数要传递对象的实例作参数,所以无法对抽象(未实例化)的对象之间建立连接关系。这些信号/槽的连接是在类外定义的(上述3个对象的连接关系是在main.cpp中面向这3个类的具体实例来定义的,与类的定义无关系)。

互相独立的组件+ 可靠的信号/槽机制=功能完善的软件

在一个项目中,假如我是PM,那么只要我们确定好项目中各组件的“信号/槽”连接关系后,我们就可以将这个项目分解为若干个相互独立,无不干扰的的部分,开发过程在只要严格尊守约定好的信号和槽就可以了,待各部分组件

完成后,建立后组件的实例间的“信号/槽”关系好,这个项目就完成了。。。嗯,这思想,这开发模式,不正是全世界开发者所追求的目标吗??SRC:

main.cpp

#include

#include"widget.h"

#include"FullEdit.h"

#include"PicSee.h"

int main(int argc, char *argv[])

{

QApplicationa(argc, argv);

Widget mainWindow; //主窗口

FullEditFEdit; //全屏截图器

PicSeePSee; //截图后的截图查看器

//mainWindow to PSee:mainWindow发出StartCut信号后,PSee先最小化,然后再隐藏

QObject::connect(&mainWindow,SIGNAL(StartCut()),&PSee,SLOT( Minimized_Hide()));

//mainWindow to FEdit:mainWindow发出StartCut信号后,FEdit先初始化再全屏显示

QObject::connect(&mainWindow,SIGNAL(StartCut()),&FEdit,SLOT (Init_FCShow()));

////----------------------------------------------------------------

//当FEdit发出FinishCut信号时,mainWindow接收图片指针,并显示窗口(showNormal)

QObject::connect(&FEdit,SIGNAL(FinishCut(QImage

*)),&mainWindow,SLOT(Get_Pix_Show(QImage *)));

//当FEdit发出FinishCut信号时,PSee接收图片指针,并显示窗口(showNormal)

QObject::connect(&FEdit,SIGNAL(FinishCut(QImage

*)),&PSee,SLOT(Get_Pix_Show(QImage *)));

////----------------------------------------------------------------

//当FEdit发出CancleCut截图被取消的信号,mainWindow接收后就显示主窗口

QObject::connect(&FEdit,SIGNAL(CancleCut()),&mainWindow,SLO T(showNormal()));

//mainWindow to PSee:mainWindow发出PicSaved图片保存信号后,PSee 先最小化,然后再隐藏

QObject::connect(&mainWindow,SIGNAL(PicSaved()),&PSee,SLOT( Minimized_Hide()));

mainWindow.show();

return a.exec();

}

////

widget.ui

////

widget.h

#ifndef WIDGET_H

#define WIDGET_H

#include

namespace Ui {

class Widget;

}

class Widget : public QWidget

{

Q_OBJECT

public:

explicit Widget(QWidget *parent = 0);

~Widget();

signals:

void StartCut();//表示开始截图的信号

void PicSaved();//图片成功保存的信号

public slots:

//收到FinishCut信号时,mainWindow接收图片指针,并显示窗口(showNormal)

void Get_Pix_Show(QImage *final_pix);

private slots:

void on_CutButton_clicked();

void on_SaveButton_clicked();

private:

Ui::Widget *ui;

QImagefinal_pix; //最终的截图

};

#endif// WIDGET_H

////

https://www.doczj.com/doc/6711204691.html,p

#include"widget.h"

#include"ui_widget.h"

#include

#include

#include"FullEdit.h"

Widget::Widget(QWidget *parent) :

QWidget(parent),

ui(new Ui::Widget)

{

ui->setupUi(this);

this->setFixedSize(265,90);

this->setWindowTitle("WindowCut RC 3.1");

}

Widget::~Widget()

{

delete ui;

}

/**

按钮Cut被按下后,截图查看器PSee隐藏,主窗口隐藏,然后调用全屏截图器FEdit的

init()来获得

当前窗口的背景,并全屏显示

*/

void Widget::on_CutButton_clicked()

{

this->showMinimized();

this->hide();

emit StartCut(); //发出开始截图StartCut信号

}

/**

保存按钮按下后,选择保存的位置,然后保存,保存成功后,截图查看器PSee隐藏,否则发出warning

*/

void Widget::on_SaveButton_clicked()

{

QStringsaveName = QFileDialog::getSaveFileName

(this, tr("Save File"),"/",

tr("BMP File(*.BMP);; PNG File(*.PNG);; JPEG

File(*.JPG)"));

if(saveName.isNull()) //没有选择路径,则返回主窗口

return;

if(final_pix.save(saveName))

emit PicSaved(); ////图片成功保存的信号

else

QMessageBox::warning(this,"SaveError","Save Error");

}

/**

Get_Pix() 是下个SLOT,当FEdit发出Send_Pix信号时,主窗口就用Get_Pix来接收发出的图片指针

然后Enable保存按钮,显示主窗口,

然后将此图片的指针发给截图查看器PSee,并在截图查看器PSee显示此图片

*/

void Widget::Get_Pix_Show(QImage *final_pix)

{

this->final_pix = *final_pix; //接收发出的图片指针

ui->SaveButton->setEnabled(true); //这里可保存了,则使保存按钮显示

this->showNormal();//

}

////

FullEdit.h

#ifndef FULLEDIT_H

#define FULLEDIT_H

#include

class QPixmap;

class FullEdit : public QWidget

{

Q_OBJECT

public:

explicit FullEdit(QWidget *parent = 0);

QImageConverToShadow(QImage pix); //将原图转换为半透明的图片

//从原图pre在载取坐标(x1,y1),(x2,y2)所包围的部分区域的图片

QImage _Cut(QImagepre,int x1,int y1,int x2,int y2);

signals:

void FinishCut(QImage *final_pix); //当用户释放左键时,用signal发送图片的指针

void CancleCut(); //当用户在FullEdit上单击左键时,发出截图取消信号

public slots:

//收到StartCut信号后,FullEdit先初始化,记录下此时刻的屏幕背景,并全屏显示

void Init_FCShow();

protected:

void mousePressEvent(QMouseEvent *);

void mouseMoveEvent(QMouseEvent *);

void mouseReleaseEvent(QMouseEvent *);

void paintEvent(QPaintEvent *);

private:

QImage _screen; //存放当前的全屏的截图

QImage _shadow; //存放当前全屏截图的半透明的幅本

int x1,y1,x2,y2; //当前选定区域的两角的坐标

bool isLeftDown; //记录当前左键是否被按下

};

#endif// FULLEDIT_H

////

FullEdit.cpp

#include"FullEdit.h"

#include

#include

#include

#include

//#include

//#define myDebug

#ifdef myDebug

#include

#include

#endif

FullEdit::FullEdit(QWidget *parent):

QWidget(parent)

{

//omp_set_num_threads(omp_get_max_threads());

#ifdef myDebug

qDebug()<<"omp_get_max_threads(): "<

qDebug()<<"omp_get_num_threads(): "<

#endif

}

//收到StartCut信号后,FEdit先初始化再全屏显示

void FullEdit::Init_FCShow() //初始化,并记录下此时刻的屏幕背景

{

//取得当前全屏的窗口

_screen =

QPixmap::grabWindow(QApplication::desktop()->winId()).toImage( );

//取得当前全屏截图的半透明的幅本

_shadow = ConverToShadow(_screen);

//位置"左键被按下"的标志

isLeftDown = false;

this->showFullScreen(); //全屏显示

}

/**

将原图转换为半透明的图片

原理: 取得原图pix转换为QImage::Format_ARGB32格式的副本

此时得到的副本每个像素的格式为 0xAARRGGBB

其alpha通道 AA 一定 == FF(255)

然后我们将alpha通道改为(127),这样得到的就是半透明的效果

*/

QImageFullEdit::ConverToShadow(QImage pix)

{

//取得原图pix转换为QImage::Format_ARGB32格式的副本QImagetmp = pix.convertToFormat(QImage::Format_ARGB32);

int w = tmp.width();

int h = tmp.height();

//处理每一个像素

//#pragma omp parallel for

for(int i=0; i

for(int j=0; j

{

QRgb col = QRgb((tmp.pixel(i,j)<<1)>>1); //将a通道设为127 tmp.setPixel(i,j,col);

}

return tmp;

}

/////////

template

inlinevoid swap(T &a, T &b)

{

a ^= b;

b ^= a;

a ^= b;

}

/**

//从原图pre在载取坐标(x1,y1),(x2,y2)所包围的部分区域的图片

就是建一个QImage对像,其大小就是截图区域的大小,

然后向这个对像中填充原图中对应的像素就可以了

*/

inline QImageFullEdit::_Cut(QImagepre,int_x1,int_y1,int_x2,int _y2)

{

#ifdef myDebug

clock_t t = -clock();

#endif

if(_x1 > _x2) swap(_x1,_x2);

if(_y1 > _y2) swap(_y1,_y2); //使(x1,y1)为left-top坐标, (x2,y2)为right-bottom坐标

int h = _x2 - _x1;

int w = _y2 - _y1;

QImagetmp(h,w,QImage::Format_RGB32);

QRgb col;

//#pragma omp parallel for

for(int x=0; x

for(int y=0; y

{

col = pre.pixel(_x1+x,_y1+y);

tmp.setPixel(x,y,col);

}

#ifdef myDebug

t += clock();

qDebug()<<"t: "<

#endif

return tmp;

}

/**

左键被按下,记录起始坐标记录当前左键是被按下

如果是右键的话,通常就是想放弃截图,所以隐藏全屏截图器FullEdit,

然后发出窗口已隐藏的信号来通知主窗口

*/

void FullEdit::mousePressEvent(QMouseEvent *event)

{

if(event->button() == Qt::LeftButton) //左键被按下,记录起始坐标 {

x1 = event->pos().x();

y1 = event->pos().y();

isLeftDown = true; ////记录当前左键是否被按下

}

else//右键被按下,则放弃截图并退出

{

this->hide();

emit CancleCut(); //发出CancleCut取消截图信号

}

}

void FullEdit::mouseMoveEvent(QMouseEvent *event)

{

if(event->buttons() &Qt::LeftButton) //左键被按下

{

x2 = event->pos().x();

y2 = event->pos().y();

update(); //截图区域被改变,则重绘窗口

}

}

/**

如果左键被释放,则用QImage对像记录截图区域,隐藏当前窗口,然后用信号机制将这个对象的指针发出

*/

void FullEdit::mouseReleaseEvent(QMouseEvent *event)

{

if(event->button() == Qt::LeftButton)

{

isLeftDown = false; ////记录当前左键是否被按下,这里是"否"

x2 = event->pos().x();

y2= event->pos().y(); //记录截图区域的对角的坐标

if(x1 > x2) swap(x1,x2);

if(y1 > y2) swap(y1,y2); //使(x1,y1)为left-top坐标, (x2,y2)为right-bottom坐标

//记录截图区域

QImage *_final_screen =

new QImage(this->_Cut(_screen,x1,y1,x2,y2));

this->hide(); //截图完成后,使这个窗口设为hide

emit FinishCut(_final_screen); //当用户释放左键时,发出FinishCut截图完成信号

}

}

/**

全屏截图器的重绘,就是先绘制半透明背景,

然后从原背景中cut一个当前选中的区域,并绘在半透明背景的上方

再绘出蓝色边框包围起截图的区域,用于提示

*/

void FullEdit::paintEvent(QPaintEvent *)

{

QPainterpaint(this);

//绘制半透明背景

paint.drawImage(0,0,_shadow);

if(isLeftDown)

{

//从原背景中cut一个当前选中的区域,并绘在半透明背景的上方QImagetmp = this->_Cut(_screen,x1,y1,x2,y2);

int lx = (x1<=x2)? x1:x2;

int ly = (y1<=y2)? y1:y2;

paint.drawImage(lx,ly,tmp);

//

//用蓝色边框包围起截图的区域

QPenmyPen;

myPen.setWidth(1);

myPen.setColor(Qt::blue);

paint.setPen(myPen);

paint.drawLine(x1,y1,x1,y2);

paint.drawLine(x1,y1,x2,y1);

paint.drawLine(x1,y2,x2,y2);

paint.drawLine(x2,y1,x2,y2);

//

}

}

////

PicSee.h

#ifndef PICSEE_H

#define PICSEE_H

#include

class PicSee : public QWidget

{

Q_OBJECT

public:

explicit PicSee(QWidget *parent = 0);

public slots:

void Minimized_Hide(); //收到StartCut信号后,先最小化,然后再隐藏

//收到FinishCut,PSee接收图片指针,并显示窗口(showNormal)

void Get_Pix_Show(QImage *final_pix);

protected:

void paintEvent(QPaintEvent *);

private:

QImage *_pix;

};

#endif// PICSEE_H

////

PicSee.cpp

#include"PicSee.h"

#include

PicSee::PicSee(QWidget *parent):

QWidget(parent)

{

this->setWindowTitle("WindowCut RC 3.1");

}

void PicSee::paintEvent(QPaintEvent *)

{

QPainterpainter(this);

painter.drawImage(0,0,*_pix);

}

void PicSee::Minimized_Hide() //收到StartCut信号后,先最小化,然后再隐藏

{

this->showMinimized();

this->hide();

}

void PicSee::Get_Pix_Show(QImage *final_pix)

{

this->_pix = final_pix;

this->setFixedSize(_pix->size()); //将此图片的指针发给截图查看器PSee

this->showNormal(); //在截图查看器PSee显示此图片

}

////

相关主题
文本预览
相关文档 最新文档