一种基于OSG的自定义事件方法
By CWorld
引头
工作以后,终于又有机会用OSG了,也把以前学生时代没有解决问题解决下,给OSG 社区做做贡献,众人拾柴火焰高嘛。本文主要是根据OSG的自定义事件机制,针对我们常用的MFC程序、QT程序等界面GUI常见的事件,比如点击Button按钮,点击菜单切换等事件,探讨在OSG中自定义事件和解决方法。鉴于水平有限,仅仅是抛砖引玉,有错误之处,还望大家指证。
概述
本文内容主要是讨论OSG自定义事件的原因、在MFC、QT等中如何设计和事件、并提供一个mfc+osg的简单例子,最后针对OSG的事件谈谈自己的理解。
问题描述
自定义事件的原因,我们经常在使用MFC或者QT开发OSG程序时,遇到比如我点击一个控件、双击一个Button,对OSG场景进行切换的情况。这个时候,我们如何设计呢?
以MFC+OSG的程序为例,比如我们在MFC+OSG程序里,对一个菜单添加了响应函数,进行模型的切换,即把当前的牛模型,替换为滑翔机模型。
常见的方法
对于“替换模型”菜单,我们在View类的响应函数里,对OSG的数据进行修改。例如
其中replaceModel是我们写的一个函数内容如下:
在绝大多事情下,这种方式,预期的结果是正确的,即我们的程序替换了OSG的模型。但是如果你用一个面片数目非常大的模型进行测试,就会出现Vector<>的地址内存错误。这
是什么原因呢?让我们来看看MFC+OSG程序的线程模型吧。
MFC +OSG的线程模型
通过如下的图,我们可以清楚的看到在CView类,我们启动了OSG的渲染线程,所以在整个程序里,我们存在了两个线程,MFC-UI线程,OSG线程。
一个比较明显的例子就是,我们如果在MFC+OSG程序里加载一个复杂的模型,你会发现你的鼠标还是可以移动的。对比MFC+OpenGL的程序,比如我们在OnDraw()函数里,响应绘制,你会发现加载一个复杂的3DS模型,你的鼠标是动不了的。
根据上面的描述,我们可以判断这样直接在菜单响应函数里OnReplacemodel()里,直接更新OSG数据是错误的,因为学过多线程设计的我们都知道,对一个共享的数据在其他的线程里更新,在不加锁的情况下,它的结果是不可预期的,也就存在了上面所说的Vector()的错误。
比较笨拙的办法
在我还是学生的时候,因为项目紧张,理论素质和C++水平不到家,对于Array说的自定义事件,什么Command Buffer事件队列之类的,总是不了解,当然也不敢用,当时就觉得先做完再说吧。于是,我选择了一个最笨的办法,我对root节点设置回调,在OnReplacemodel()函数里,设置bool变量,来触发回调替换模型,具体的思路如下:breplace=true;
相信,大家在看了诸多回调函数的例子,大家都能明白这种对节点设置回调,利用Bool变量来更新OSG数据的笨办法,
这个办法的好处就是,比较简单,容易实现,当然这实在不是一个优雅和高效的解决办法,毕竟每次节点都会在更新时调用这个函数。而且菜单单击属于一种事件,我们应该针对事件设置回调函数,但是OSG是通用渲染引擎,不会为了MFC、Qt提供菜单、按钮这样的事件类型。所以我们只能自定义事件。
自定义事件思路
OSG中的事件,
以GUIEventAdapter为例,代码在osgGA/GUIEventAdapter中,我们可以看到OSG有如下事件:
基本思路:
在MFC中,存在两个线程(MFC+UI)线程和OSG线程,简单的我们可以认为存在两个事件队列,即MFC的事件队列和OSG的事件队列,我们的思路就是在菜单响应函数里,把我们的自定义事件压入OSG的事件队列,然后在OSG的渲染线程里进行处理。具体思路如下图:
OSG线程
如何自定义事件
关于如何自定义事件,我参考的是Array的《OSG3+Beginners+Guide》一书,这里说句抱歉,本来工作了,也有钱了应该买正版,支持Array的工作,不过在Amazon一看,都是dollar呀,考虑到1比6的汇率,还是免不了俗,不知道哪位好心的网友在网上上传了电子书,自己就打印了一本。废话少说了。
下面我们以替换模型和给模型添加包围盒为例,来谈谈如何结合mfc+osg来实现自定义事件,压入事件队列,如何处理自定义事件。
自定义事件类型
首先定义事件类型枚举,并增加一个事件类,具体如下
然后添加事件类OwnDefineEventAdpater类,其中m_eventType用来设置我们的事件类
对于我们常见的事件处理函数框架,大家想必都不陌生,如下图所示:
于是我们在 Frame里添加每帧处理的事件,在osgGA::GUIEventAdapter::USER里,我们就可以处理我们的事件了。接下来的问题就是如何添加自定义事件。
添加自定义事件原理
在OSG的事件队列里有EventQueue::userEvent()函数,可以添加自定义事件,
在source\src\osgGA\EventQueue.cpp的383行,我用的是osg2.8.2的源代码,可以看到userEvent()函数会把每个用户自定义的事件一个个的添加到队列里。
那么我们就可以按照这种方式,在我们的CView里把事件压入OSG的事件队列,并且我们的基本事件类型都是GUIEventAdapter::User类型的,然后在USER类型里,我们在进行我们具体的事件分类,即是包围盒事件还是替换模型事件等,具体的压入事件方法如下图所示:
如何自定义处理事件
对于osgGA::GUIEventHandler类,我们都知道重载:
virtual bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )方法,来进行事件处理,比如我们的这个例子,就可以这样如下图所示:在User事件类型里,取出我们的事件类OwnDefineEventAdapter类,然后根据各自的子事件类型,进行处理。
探讨
这里有一个需要探讨的设计问题,请大家注意,只是我的个人看法,仅仅是探讨。
对于osgGA:: GUIEventAdapter类,我们知道它的事件类型只有上面那幅图的PUSH、KEYDOWN等,我本打算直接扩展GUIEventAdapter类,即在USER事件类型后,派生我们自己的事件,
诸如Class myGUIEevnetAdapter: public handler
这样在来扩展我们的事件,但是,事件处理函数Handle,具体如下,
virtual bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )的处理参数,osgGA::GUIEventAdapter& ea,这个引用形式,会造成类型不匹配,编译不过,所以觉得这里也许改为,或者基类类型指针也许更好。即如下
virtual bool handle( const osgGA::GUIEventAdapter* ea, osgGA::GUIActionAdapter& aa ) 这样在handle里,我们就可以直接自定义事件,而不是USER事件的子类型事件,当然对于OSG的具体机制,自己还不了解,所以不知道这个想法是否合理。
附源代码
鉴于语言表达能力不好,这里附源代码和项目工程文件。Osg2.8.2, vs2008,mfc
参考资料
Array的OSG3+Beginners+Guide
QT习题 一、名词解释 1、虚函数: 2、回调函数: 3、内联函数: 4、信号与插槽: 5、私有函数: 6、构造函数: 7、公有函数: 8、内联函数: 9、信号与插槽: 10、析构函数: 二、判断题 1、在QT中Qwidget不可以作为应用程序的窗口()。 2、在创建窗口部件的时候,窗口部件通常不会显示出来()。 3、布局管理器不是一个窗口部件() 4、FindDialog(QWidget *parent = 0);父参数为NULL,说明有父控件。() 5、show()显示的对话框是模式对话框。用exec()显示的对话框是无模式对话框。 () 6、布局管理器派生自QObject。() 7、Q_OBJECT是一个宏定义,如果类里面用到了signal或者slots,就必须要声 明这个宏。() 8、FindDialog(QWidget *parent = 0);父参数为NULL,说明没有父控件。() 9、槽可以是虚函数,可以是公有的,保护的,也可是私有的。() 10、show()显示的对话框是无模式对话框。用exec()显示的对话框是模式对话 框。() 三、简答题 1、简述一下信号与插槽机制。 2、简述布局管理器的功能,列举3个布局管理器。 3、简述使用Qt设计师,在创建对话框时主要包含哪几个基本步骤? 4、GUI程序通常会使用很多图片,请简述3种提供图片的方式。 5、列举几种Qt中会产生绘制事件的情况。 6、Update()与repaint()之间的区别? 7、对窗体上的控件进行布局管理一般有哪几种方式,简述一下其缺点。 8、简述事件和信号的特点和区别。 9、简述主函数中创建QApplication对象功能。 10、简述使用Qt设计师,在创建对话框时总是包含哪几个基本步骤?
编写多窗口程序 导语 程序要实现的功能是:程序开始出现一个对话框,按下按钮后便能进入主窗口,如果直接关闭这个对话框,便不能进入主窗口,整个程序也将退出。当进入主窗口后,我们按下按钮,会弹出一个对话框,无论如何关闭这个对话框,都会回到主窗口。 程序里我们先建立一个工程,设计主界面,然后再建立一个对话框类,将其加入工程中,然后在程序中调用自己新建的对话框类来实现多窗口。 在这一篇还会涉及到代码里中文字符串显示的问题。 目录 一、添加主窗口 二、代码中的中文显示 三、添加登录对话框 四、使用自定义的对话框类 正文 一、添加主窗口 1.我们打开Qt Creator,新建Qt Gui应用,项目名称设置为“nWindows”,在类信息界面保持基类为QMainWindow,类名为MainWindow,这样将会生成一个主窗口界面。 2.完成项目创建后,打开mainwindow.ui文件进入设计模式,向界面上拖入一个Push Button,然后对其双击并修改显示文本为“按钮”,如下图所示。 3.现在运行程序,发现中文可以正常显示。在设计模式可以对界面进行更改,那么使用代码也可以完成相同的功能,下面就添加代码来更改按钮的显示文本。
二、代码中的中文显示 1.我们点击Qt Creator左侧的“编辑”按钮进入编辑模式,然后双击mainwindow.cpp文件对其进行编辑。在构造函数MainWindow()中添加代码: MainWindow::MainWindow(QWidget*parent): QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->pushButton->setText("新窗口");//将界面上按钮的显示文本更改为“新窗口”} 这里的ui对象就是界面文件对应的类的对象,在mainwindow.h文件中对其进行了定义,我们可以通过它来访问设计模式添加到界面上的部件。前面添加的按钮部件Push Button,在其属性面板上可以看到它的objectName属性的默认值为pushButton,这里就是通过这个属性来获取部件对象的。 我们使用了QPushButton类的setText()函数来设置按钮的显示文本,现在运行程序,效果如下图所示。 2.我们发现,在代码中来设置按钮的中文文本出现了乱码。这个可以有两种方法来解决,一个就是在编写程序时使用英文,当程序完成后使用Qt语言家来翻译整个软件中的显示字符串;还有一种方法就是在代码中设置字符串编码,然后使用函数对要在界面上显示的中文字符串进行编码转换。因为翻译一个软件很麻烦,对于这些小程序,我们希望中文可以立即显示出来,所以下面来讲解第二种方法。 3.设置字符串编码,可以使用QTextCodec类的setCodecForTr()函数,一般的使用方法就是在要进行编码转换之前调用该函数,下面我们在main.cpp文件中添加代码:
Swing 常用事件和监听器接口 AncestorEvent AncestorListener ancestorAdded(AncestorEvent e) ancestorMoved(AncestorEvent e) ancestorRemoved(AncestorEvent e) CaretEvent 通知感兴趣的参与者事件 源中的文本插入符已经发 生更改 CaretListener caretUpdate(CareEvente) ChangeEvent 通知感兴趣的参与者事件 源中的状态已经发生更改 ChangeListener stateChanged(ChangeEvent e) HyperlinkEvent 通知感兴趣的参与者发生 了与超文本链接有关的事 情 HyperlinkListener hyperlinkUpdate(HyperlinkEvent e) InternalFrameEvent 以事件源的形式添加对J InternalFrame对象的支持的 A WTEvent InternalFrameListener internalFrameActivated(InternalFrameEvent e) internalFrameClosed(InternalFrameEvent e) internalFrameClosing(InternalFrameEvent e) internalFrameDeactived(InternalFrameEvent e) internalFrameDeiconified(InternalFrameEvent e) internalFrameIconified(InternalFrameEvent e) internalFrameOpened(InternalFrameEvent e) ListDataEvent 定义一个列表更改的事件ListDataListener contentsChanged(ListDataEvent e) intervalAdded(ListDataEvent e) intervalRemoved(ListDataEvent e)
Qt Creator 窗体控件自适应窗口大小布局 常见的软件窗口大小改变(最大化、手动改变时)需要窗口的部件能够自适应布局,而在Qt的应用程序界面设计中,对于像我一样的初学者如何实现窗口自适应调整还是要绕点弯路的。网上百度了很多,多数说的很含糊,还有很多是用程序实现的,既然已经有Qt Creator那么高集成度的工具了,我还是倾向于直接在Qt Creator中通过可视化配置的方式完成,一是所见即所得,而是效率要高不少。 Qt中如果想实现窗体内空间随着窗体大小调整,必须使用布局管理,常用的布局管理有QHBoxLayout、QVBoxLayout、QGridLayout,空的地方使用spacer 控件进行填充,因此首先将窗体空间使用布局管理典型应用如下图所示。 我这里使用QGridLayout,按住Ctrl多选需要布局的窗体控件,右键-布局-栅格化局,根据需要进行调整。 要想是控件根据窗体进行调整,最为重要的一点就是设置窗口部件的大小策略,各控件均有这一项设置,如下图所示。
这部分具体的参数解释摘录如下: 结合控件的SizePolicy属性,来控制布局管理中的控件的尺寸自适应方式。 控件的sizePolicy说明控件在布局管理中的缩放方式。Qt提供的控件都有一个合理的缺省sizePolicy,但是这个缺省值有时不能适合所有的布局,开发人员经常需要改变窗体上的某些控件的sizePolicy。一个QSizePolicy的所有变量对水平方向和垂直方向都适用。下面列举了一些最长用的值: A. Fixed:控件不能放大或者缩小,控件的大小就是它的sizeHint。 B. Minimum:控件的sizeHint为控件的最小尺寸。控件不能小于这个sizeHint,但是可以 放大。 C. Maximum:控件的sizeHint为控件的最大尺寸,控件不能放大,但是可以缩小到它的最小 的允许尺寸。
#include
【原创】Qt自定义窗口部件 QtDesigner自定义窗口部件有两种方法:改进法(promotion)和插件法(plugin)改进法 1、改进法之前,要先写好子类化QSpinBox后的HexspinBox.h和HexspinBox.cpp文件。把这两个文件拷贝到想要的项目中。 HexspinBox.h HexspinBox.cpp
2、在需要开发的项目中的窗口中, 1、用Qt Designer创建一个新的窗体main.ui,把控件箱里的QSpinBox添加到窗体中。 2、右击微调框,选择“Promote to ”上下文菜单。 3、在弹出的对话框中,类名处填写“HexSpinBox”,头文件填写“hexspinbox.h” 好了。在ui生成的包含有QSpinBox的控件文件中,ui的源代码里面多了一段
可以在VS2008中编译一下main.ui文件,从ui_main.h源代码中可以知道,引入的控件是: 升级法的缺点是不能在Qt Designer中设置自定义控件自己的特有属性,也不能够绘制自己。这些问题可以用插件法解决。 插件法 1.VS中创建Qt4 Design Plugin 工程,名称叫custom 自动建立如下几个文件: 自定义控件:custom.h,custom.cpp 插件:customplugin.h,customplugin.cpp 源代码如下:
JAVA四种方法实现事件监听 1.外部类实现事件监听: import java.awt.*; import java.awt.event.*; import javax.swing.*; publicclass Listener1extends JFrame { JButton button1,button2; JPanel pane1,pane2,p1,p2; CardLayout card1=new CardLayout(); /*CardLayout布局方式将容器中的每个组件看作一张卡片。 一次只能看到一张卡片,容器则充当卡片的堆栈*/ Listener1(){ this.setTitle("外部类实现事件监听"); this.setBounds(200,200,300,200); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); init(); } publicvoid init(){ p1=new JPanel(); p1.add(new JLabel("第一个面板")); p1.setBackground(Color.red); p2=new JPanel(); p2.add(new JLabel("第二个面板")); p2.setBackground(Color.green); pane1=new JPanel(card1); pane1.add("红色", p1); pane1.add("绿色", p2); button1=new JButton("红色"); button2=new JButton("绿色"); pane2=new JPanel(); pane2.add(button1); pane2.add(button2); this.add(pane1,BorderLayout.CENTER); this.add(pane2,BorderLayout.SOUTH); button1.addActionListener(new ColorEvent(card1,pane1));
1Qt4界面开发 1.1Q t历史 Qt是一个用于桌面系统和嵌入式开发的跨平台应用程序框架。它包括一个直观的API 和一个丰富的类库,以及用于GUI开发和国际化的集成工具,另外它支持Java?和C++开发。Qt让企业无须重新编写源代码,便可以构建运行在不同桌面操作系统和嵌入式设备上的软件应用程序。 Qt框架最早可公开获取是在1995年5月。最初是由Haavard Nord(TrollTech公司的首席执行官)和Eirik Chambe-Eng(TrollTech公司的董事会主席)。Haavard和Eirik 最早在特隆赫姆的挪威技术学院相遇,在那里他们双双获得了计算机科学硕士学位。 早在1991年,Haavard 就开始写一些最终成为Qt的类,并和 Eirik合力设计。在接下来的一年,Eirik提出了“信号和槽”的思想,一个现在已经被一些其他套装工具包含简单但功能强大的GUI编程范式。Haavard 接受了这一思想并手工生成了这一思想的代码实现。到1993年,Haavard和Eirik已经完成了Qt的第一个图形内核的开发并能用它来实现一些他们所需的物件。在这一年的年末,Haavard建议他们一起去经商,创建一个“世上最好的C++ GUI框架”。 字母“Q”被选为类的前缀是因为这个字母在Haavard的Emacs字体中看起来很漂亮。受到Xt(the X toolkit)的启发,字母“t”被追加来表示“toolkit”。公司在1994年5月4日成立,起初被命名为“Quasar Technologies”,之后被改名为“Troll Tech”,今天则被称为奇趣科技(Trolltech)。 1995年5月20日,Qt 0.90被上传到https://www.doczj.com/doc/f515619772.html,。六天后,这一发布在comp.os.linux.announce被宣布。这是Qt的第一个公共发行版。Qt可以被用在Windows 和Unix开发中,在两个系统中提供相同的API。Qt从一开始就可以在两种许可协议下获取:一个是商业开发中需要的商业许可协议,一个用于开源开发的自由软件版。 1996年3月,欧洲航天局成为Qt的第一个客户,一下买了十个Qt商业许可。Qt 0.97在同年的5月底发布,1996年9月24日,Qt 1.0发布。到了同年年底,Qt到达了版本1.1;拥有8个客户,每一个都在不同的国家,他们购买了18个商业许可。 Qt 1.2 在1997年4月发布。Matthias Ettrich利用Qt构建KDE的决定帮助Qt成为Linux C++ GUI 开发的实际标准,1997年9月Qt 1.3发布。 1998年9月,Qt 1的最后一个主要发行版1.40发布。Qt 2.0于1999年7月发布。Qt 2有了一个新的开源许可协议,发布许可协议(QPL),遵守开源的定义。1999年8月,Qt赢得了LinuxWorld的“最佳开发库/工具”大奖。 2000年奇趣科技发布了Qtopia核心(后来成为Qt/Embedded)。它被设计用来运行在嵌入式Linux设备上并提供了自己的窗口系统作为X11的一个轻量级代替。现在Qt/X11和Qtopia核心都可以通过GNU通用许可(GPL)获取。到2000年年底,奇趣科技成立了Trolltech Inc.(USA)并且发布了Qtopia的第一个版本,一个移动电话和PDAs应用程序平台。Qtopia赢得了2001和2002年LinuxWorld的“最佳嵌入式 Linux 解决方案”大奖,
第八讲AWT和事件监听打印本页 1 基本概念 下面几讲,我们就来学习AWT的各种容器和组件,并重点学习AWT的事件监听和处理方法。由于学习事件需要用到一些简单的构件,我们先学习几个简单的构件。现在,我们先来介绍AWT里面几个重要的概念:构件,容器,布局管理器和事件监听(AWT P4)。 1.1构件是图形用户界面的最小单位之一,它里面不再包含其他的成分. 构件的作用是完成与用户的一次交互,包括接受用户的一个命令,接受用户的一个文本输入,向用户显示一段文本或一个图形等。常用的构件有: 按钮构件 项目选择构件:复选框(Checkbox)列表(List或Choice) 文本构件:文本框文本区 对话框构件:对话框文件对话框提示框帮助 菜单构件:弹出式菜单复选框菜单 1.2容器 容器是用来组织构件的单元。常用的容器有:面板、窗口。 1.3布局管理器: 布局管理器用来布置容器和容器中的各个构件,比如他们的大小、位置等。AWT提供了几种标准的布局管理器。 1.4事件监听 要使点击鼠标、敲打键盘等实现特定的动作,我们需要捕捉事件并且加以实现。AWT里典型的事件有:鼠标事件、鼠标移动事件、键盘事件、窗口事件等。 我们通过学习最基本的构件和容器(标签、按钮和面板)来粗略理解这些概念。标签和按钮是显示标签的简单构件;而面板是AWT提供的最基本的容器。 2 几个简单的构件和容器 标签(https://www.doczj.com/doc/f515619772.html,bel) 标签用来显示文本。 演示(StarterApplet) 面板(java.awt.Panel) 面板是一个通用的容器,在上面可以放置各种构件。 我们经常用的Applet类,其实就是面板的一个子类 按钮(java.awt.Button) 按钮具有三维外型,当它们被激活时触发按钮事件,用户可以根据按钮事件,做出适当的反应,比如执行一系列操作等。 演示 3 事件 AWT有两种事件处理模型:一种是基于继承的模型,它在AWT1.1或以前的版本中使用,现在已经逐渐被淘汰;另一种是基于授权的事件模型。我们主要学习给予授权的事件模型。 授权事件模型的原理很简单:事件源激发事件、事件监听器监听事件,最后执行事件。可以通过调用addXYZListener(XYZListner)方法向构件注册监听器。把监听器加到构件中以后,如果构件激发相应类型的事件,
RadioButton使用说明 2012-01-19 RadioButton(单选按钮)在Android开发中应用的非常广泛,比如一些选择项的时候,会用到单选按钮。它是一种单个圆形单选框双状态的按钮,可以选择或不选择。在RadioButton 没有被选中时,用户能够按下或点击来选中它。但是,与复选框相反,用户一旦选中就不能够取消选中。 实现RadioButton由两部分组成,也就是RadioButton和RadioGroup配合使 用.RadioGroup是单选组合框,可以容纳多个RadioButton的容器.在没有RadioGroup 的情况下,RadioButton可以全部都选中;当多个RadioButton被RadioGroup包含的情况下,RadioButton只可以选择一个。并用setOnCheckedChangeListener来对单选按钮进行监听。 private RadioButton rB_boy; private RadioButton rB_girl; private RadioGroup rG_content; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(https://www.doczj.com/doc/f515619772.html,yout.main); //RadioGroup this.rG_content=(RadioGroup)findViewById(R.id.rG_Con); //RadioButton this.rB_boy=(RadioButton)findViewById(R.id.rd_boy); this.rB_girl=(RadioButton)findViewById(R.id.rd_girl); this.rB_boy.setText("这是男"); this.rB_girl.setText("这是女"); //添加事件监听器 this.rG_content.setOnCheckedChangeListener(new OnCheckedChangeListener(){ public void onCheckedChanged(RadioGroup group, int checkedId) { if(checkedId==R.id.rd_boy) { Toast.makeText(getApplicationContext(), "你选择的是男孩!",Toast.LENGTH_SHORT).show();
因为标题栏属于窗口管理器控制,也就受限于操作系统,所以直接利用Qt来修改是不可行的! 通常情况下利用Qt我们 可以自定义标题栏,这里提供一个简单的例子! 例子比较简,大致思路是正常创建窗口后,屏蔽标题栏,通过布局将一个QLabel和三个按钮构成一个“标题栏” 放置在顶端(视个人喜好,位置可以任意放置),重新实现必要的事件。 下面分步骤进行:
1. 创建窗口,屏蔽标题栏 例子中是创建了一个MainWindow窗口,构造过程中传入Qt::FramelessWindowHint 参数. customTitleBar::customTitleBar(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, Qt::FramelessWindowHint) { ui.setupUi(this); ui.menuBar->hide(); ui.statusBar->hide(); ...... } 2. 将自定义的“标题栏”放入窗口中 这里我们直接用QDeisgner进行设计,设计完成后利用布局将其置于顶端即可.
3. 事件处理在这里我们只是简单实现鼠标操作窗口的放大、缩小和移动, 所以只重写鼠标事件: 单击、释放、双击和移动。 view plaincopy to clipboardprint? 1./* 2. QRect rect = ui.titleFrame->frameRect(); 3. if(rect.contains(event->pos())); 4.这两句就是用于判断鼠标位置是否落在“标题栏”内。 5.*/ 6.void Qt_Test::mousePressEvent(QMouseEvent *event) 7.{ 8. if(event->button() == Qt::LeftButton) 9. { 10. dragPosition = event->globalPos() - frameGeometry().topLeft(); 11.
编写多窗口程序 版权声明 该文章原创于Qt爱好者社区(https://www.doczj.com/doc/f515619772.html,),作者yafeilinux,转载请注明出处! 导语 程序要实现的功能是:程序开始出现一个对话框,按下按钮后便能进入主窗口,如果直接关闭这个对话框,便不能进入主窗口,整个程序也将退出。当进入主窗口后,我们按下按钮,会弹出一个对话框,无论如何关闭这个对话框,都会回到主窗口。 程序里我们先建立一个工程,设计主界面,然后再建立一个对话框类,将其加入工程中,然后在程序中调用自己新建的对话框类来实现多窗口。 在这一篇还会涉及到代码里中文字符串显示的问题。 目录 一、添加主窗口 二、代码中的中文显示 三、添加登录对话框 四、使用自定义的对话框类 正文 一、添加主窗口 1.我们打开Qt Creator,新建Qt Gui应用,项目名称设置为“nWindows”,在类信息界面保持基类为QMainWindow,类名为MainWindow,这样将会生成一个主窗口界面。 2.完成项目创建后,打开mainwindow.ui文件进入设计模式,向界面上拖入一个Push Button,然后对其双击并修改显示文本为“按钮”,如下图所示。
3.现在运行程序,发现中文可以正常显示。在设计模式可以对界面进行更改,那么使用代码也可以完成相同的功能,下面就添加代码来更改按钮的显示文本。 二、代码中的中文显示 1.我们点击Qt Creator左侧的“编辑”按钮进入编辑模式,然后双击mainwindow.cpp文件对其进行编辑。在构造函数MainWindow()中添加代码: MainWindow::MainWindow(QWidget*parent): QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->pushButton->setText("新窗口");//将界面上按钮的显示文本更改为“新窗口”} 这里的ui对象就是界面文件对应的类的对象,在mainwindow.h文件中对其进行了定义,我们可以通过它来访问设计模式添加到界面上的部件。前面添加的按钮部件Push Button,在其属性面板上可以看到它的objectName属性的默认值为pushButton,这里就是通过这个属性来获取部件对象的。 我们使用了QPushButton类的setText()函数来设置按钮的显示文本,现在运行程序,效果如下图所示。
关于Qt界面中对于相关控件进行布局管理 在用Qt进行用户界面应用程序的编程时,建议通过编写相关代码来生成和维护Qt控件,而不要用Qt Designer。这时对相应的Qt控件进行布局管理显得尤为重要。 常见的三种布局方式: 网格布局:QGridLayout 水平布局:QHBoxLayout 垂直布局:QVBoxLayout 步骤: 1)以单个的Qt控件为单位,先进行子块布局,分别对各个子块进行布局。 2)以步骤1)中的子块为单位,进行全局布局。 例如:我们要完成如下样式的Qt界面,整个Qt界面有ABCDEFXYZ共计9个Qt控件。 方法1: 1)用“网格布局”对ABCDEF(子块1)进行布局 QGridLayout *leftLay=new QGridLayout; 用“垂直布局”对XYZ(子块2)进行布局 QVBoxLayout *rightLay=new QVBoxLayout; 2)用“水平布局”对子块1(ABCDEF)、子块2(XYZ)进行全局布局 QHBoxLayout *mainLay=new QHBoxLayout; mainLay->addLayout(leftLay); mainLay->addLayout(rightLay); 方法2: 1)用“水平布局”对AB(子块1)进行布局 用“水平布局”对CD(子块2)进行布局 2)用“垂直布局”对子块1(AB)、子块2(CD)、E、F进行布局,形成子块3(ABCDEF)。3)用“垂直布局”对XYZ(子块4)进行布局 4)用“水平布局”对子块3(ABCDEF)、子块4(XYZ)进行全部布局
方法1: QGridLayout *leftLay=new QGridLayout; leftLay->addWidget(hostLabel,0,0); leftLay->addWidget(hostLineEdit,0,1); leftLay->addWidget(portLabel,1,0); leftLay->addWidget(portLineEdit,1,1); leftLay->addWidget(myCheckBox,2,0,1,2); leftLay->addWidget(myListWidget,3,0,1,2); leftLay->addWidget(msgLabel,4,0,1,2); QVBoxLayout *rightLay=new QVBoxLayout; rightLay->addWidget(logButton); rightLay->addWidget(sendButton); rightLay->addWidget(linkButton); QHBoxLayout *mainLay=new QHBoxLayout; mainLay->addLayout(leftLay); mainLay->addLayout(rightLay); setLayout(mainLay);
在一个应用程序设计中,为了实现一些特定的功能,必领设计自定义对话框。 自定义对话框的设计一般从 QDialog 继承,并且可以采用UI设计器可视化地设计对话框。对话框的调用一般包括创建对话框、传递数据给对话框、显示对话框获取输入、判断对话框单击按钮的返回类型、获取对话框输入数据等过程。 本节将通过实例 samp6_2 来详细介绍这些原理。图 1 是实例 samp6_2 的主窗口,及其设置表格行列数的对话框。 图 1 实例 samp6_2 主窗口及其设置表格行列数的对话框 主窗口采用 QTableView 和 QStandardltemModel、QltemSelectionModel 构成一个通用的数据表格编辑器,设计了 3 个对话框,分别具有不同的功能,并且展示对话框不同调用方式的特点: ?设置表格行列数对话框 QWDialogSize 该对话框每次动态创建,以模态方式显示(必须关闭此对话框才可以返回主窗口操作),对话框关闭后获取返回值,用于设置主窗口的表格行数和列数,并且删除对话框对象,释放内存。 这种对话框创建和调用方式适用于比较简单,不需要从主窗口传递大量数据做初始化的对话框,调用后删除对话框对象可以节约内存。
?设置表头标题对话框 QWDialogHeaders 图 2 是设置表格表头标题的对话框,该对话框在父窗口(本例中就是主窗口)存续期间只创建一次,创建时传递表格表头字符串列表给对话框,在对话框里编辑表头标题后,主窗口获取编辑之后的表头标题。 图 2 设置表格表头标题对话框 注意,对话框以模态方式显示,关闭后只是隐藏,并不删除对象,下次再调用时只是打开己创建的对话框对象。 这种创建和调用方式适用于比较复杂的对话框,需要从父窗口传递大量数据做对话框初始化。下次调用时不需要重复初始化,能提高对话框调用速度,但是会一直占用内存,直到父窗口删除时,对话框才从内存中删除。 ?单元格定位与文字设置对话框QWDialogLocate 图 3 是单元格定位和文字设置对话框,该对话框以非模态方式调用,显示对话框时还可以对主窗口进行操作,对话框只是浮动在窗口上方。在对话框里可以定位主窗口表格的某个单元格并设置其文字内容,在主窗口上的表格中单击鼠标时,单元格的行号、列号也会更新在对话框中。对话框关闭后将自动删除,释放内存。
如何在Qt中使用自定义数据类型 - zhezhelin - 博 客园 如何在Qt中使用自定义数据类型 Q_DECLARE_METATYPE,Qt自定义类型 这里我们使用下面这个struct来做说明(这里不管是struct还是class都一样): 复制代码 QVariant 为了能在QVariant中使用自定义数据类型做,需要使用 Q_DECLARE_METATYPE()来向Qt的元系统声明这个自定义类型。如下列所示: 复制代码 在作为QVariant传递自定义数据类型时,需要使用QVariant::fromValue()或者qVariantFromValue: 复制代码 为了更方便一点,你可以在自定义类型中定义一个QVariant() 类型转换符: 复制代码 这样我们便可以像下面这样使用了: 复制代码 信号和槽 对于直接连接类型(默认情况下就是直接连接)而言,使用自定义数据类型做信号参数不需要做其他其他处理,就像内置数据类型一样: 复制代码 但在跨线程时如果你还这么做,编译器就会给出警告了: 复制代码 这时我们需要先注册Player: qRegisterMetaType<Player>("Player");
qRegisterMetaType<Player>( ); (上面那个是错误的,除非名字刚好和类名一样) connect(sender, SIGNAL(playerCreated(const Player&)), receiver, SLOT(addPlayer(const Player&))); 复制代码 QDebug 最好是能这样: 复制代码 而不是这样: 复制代码 怎么做呢?我们需要对QDebug<<操作符重载一下: 复制代码 QDataStream 跟上面的QDebug很像,我们也需要重载一下<<操作符: 复制代码 QSettings 为了能在QSettings中使用自定义数据类型,需要让Qt的元系统知道有此类型,就像上面介绍QVariant部分一样,另外还要提供相应的QDataStream操作符,还必须注册这个流操作符: 复制代码 如此处理之后我们就可以像下面这样使用了: 复制代码 复制代码 参考: QString QSettingsPrivate::variantToString(const QVariant &v) { QString result;
Java的事件处理机制 概念部分: 1.事件:Event 是一种消息对象,封装了与事件发生相关的信息, 如操作键盘会引发KeyEvent事件, 单击关闭按钮会引发WindowEvent事件, 单击命令按钮或选择菜单项目会引发ActionEvent事件 等等 2.事件源:Event Source 产生事件的对象, 如命令按钮和单选按钮都是事件源,单击他们时,会引发ActionEvent事件 单选按钮会产生ItemEvent事件。 3.事件监听器:Event Listener 在事件发生时,事件源负责给予通知的一种对象。接收到事件通知的监听器主动的对事件进行处理。 两件事:将自己注册给事件源;事件的处理 4.事件处理器Event Handler 事件处理方法,用来接受事件并处理事件的方法。 Java事件处理的步骤: 1.类实现相应的事件监听器接口 2.重写接口中抽象方法 3.给事件源注册事件监听器 【例题】关闭窗口的实现
public class NotepadDemo{ private Frame mainForm; private MenuBar mb; private Menu m1; private Menu m2; private MenuItem mExit; private MenuItem mi1; private MenuItem mi2; private ExitHandler eh; public NotepadDemo(){ mainForm = new Frame(); mb = new MenuBar(); m1 = new Menu("文件(F)"); m2 = new Menu("编辑(E)"); mi1 = new MenuItem("新建 Ctrl + N"); mi2 = new MenuItem("打开 Ctrl + O"); mExit = new MenuItem("退出(X)"); mainForm.setMenuBar(mb); mb.add(m1); mb.add(m2); m1.add(mi1); m1.add(mi2); m1.add(mExit); mainForm.setBounds(0, 0, 400, 300); eh = new ExitHandler(); //注册事件监听器 mExit.addActionListener(eh); mi1.addActionListener(eh); mi2.addActionListener(eh); //注册Form的关闭监听器 mainForm.addWindowListener(eh); } public void NotepadShow(){ mainForm.setVisible(true); } public static void main(String[] args) { NotepadDemo nd = new NotepadDemo(); nd.NotepadShow();
事件监听 OSGi运行环境内部的事件主要包括三类: ?框架事件(FrameworkEvent) STARTED框架已经启动 ERROR某个Bundle启动过程中引发错误 WARNING某一Bundle引发一个警告 INFO某一Bundle引发一个INFO类型的事件 PACKAGES_REFRESHED PackageAdmin.refreshPackage操作执行完成STARTLEVEL_CHANGED StartLevel.setStartLevel操作执行完成 ?Bundle事件(BundleEvent) INSTALLED Bundle被安装到OSGi环境后系统发布该事件 RESOLVED Bundle被成功解析 LAZY_ACTIVATION Bundle将被延迟激活 STARTING Bundle正在被激活 STARTED Bundle被成功激活 STOPPING Bundle被停止 STOPPED Bundle正在被停止 UPDATED Bundle被更新 UNRESOLVED Bundle被UNRESOLVED UNINSTALLED Bundle被卸载 ?服务事件(ServiceEvent) REGISTERED服务被注册 MODIFIED服务被修改 UNREGISTERING服务正在被注销 下述代码展示了如何在Bundle组件中通过实现FrameworkListener,BundleListener和ServiceListener接口,并使用BundleContext注册监听OSGi环境的各种事件: 创建事件监听的bundle,测试的bundle
在bundle中导入jar包 具体代码如下
实验4 使用Qt 设计师创建主窗口应用 4.1. 创建主窗体 使用Qt设计师来创建主窗口应用是非常方便的,其步骤与使用代码创建基本一样。 1.选择模板 首先,创建一个窗体,选择“Main Window”模板,创建一个空的主窗体,如下图: 2.创建资源 在资源浏览器中,点击编辑资源,如下图所示:
我们将要在程序中使用图标资源,因此在资源编辑对话框中,点击新建资源,首先创建资源文件,我们就创建一个名为resource.qrc的资源文件,然后在编辑区中,再添加前缀,我们以“\”作为资源的前缀,图标文件我们都放在images目录下,然后添加图标文件将该目录下的所有文件添加即可,如下图所示: 完成之后,我们可以在资源浏览器中看到添加的各个图标资源,如下图所示: 3.创建动作 在动作编辑器中,点击新建动作,进行动作的创建,在此过程中,可以设置动作的文本(显示在菜单项上的文本),对象名称,工具提示(鼠标放在动作上时显示的提示信息),图标(也就是浏览资源管理器中的资源,选择适当的图标资源),快捷键(鼠标点击快捷键区域,然后按下希望设置的快捷键即可),如下图所示:我们创建了一个newAction动作,对应“文件”菜单下的“新建”菜单项。
通过同样的方式,我们将程序中用到的所有动作创建完成,如下图: 4.将动作添加到工具栏和菜单上 首先创建工具栏,在主窗口中右键单击即可在弹出菜单中选择“添加工具栏”来添加,如下图: 要将动作添加到菜单和工具栏上,还需要创建菜单,这通过在主窗口中的“在这里输入”之处输入菜单的文本,并修改菜单的objectName即可,有了菜单和工具栏,就可以将动作添加到菜单和工具栏上了,这很简单,只要从动作编辑器中拖动动作放到相应的菜单和工具栏上即可,摆放动作的时候,可以根据需要插入分隔符,最终的结果如下图所示(注,菜单上的动作没有显示出来,但在对象查看器中可以看到已经添加到菜单上了):