zhonghua

C++博客 首页 新随笔 联系 聚合 管理
  72 Posts :: 1 Stories :: 4 Comments :: 0 Trackbacks

#

其实很简单,代码如下:

            QComboBox *combobox = new QComboBox(this);
            QStringList strings;
            strings << tr("自由") << tr("典型") << tr("默认") ;
            combobox->addItems(strings);

posted @ 2012-03-29 15:49 米米 阅读(2748) | 评论 (0)编辑 收藏

在实现了newform的2个页面的功能以后,为了完善产品的人性化,我在第2个页面上增加了一个显示前面已经选择的路径和模板名称的功能。但是这里就遇到了一个问题,如果万一用户选择的路径和名称都太长了,那么下面在显示的时候就会截断,这就很不爽了。

      别看这个小问题,这就涉及了2个技巧。

1. 让QLabel自适应text的大小,直接用下面的代码:

LabelName->adjustSize();

2. 让QLabel能够自动判断并换行显示:

LabelName->setGeometry(QRect(328, 240, 329, 27*4));  //四倍行距

LabelName->setWordWrap(true);
LabelName->setAlignment(Qt::AlignTop);

       还是那句话,别看就实现了这么一个小功能,前期的摸索可真是痛苦。。新手伤不起啊。。

posted @ 2012-03-29 15:48 米米 阅读(3705) | 评论 (3)编辑 收藏

Qt中使用图片资源的方法有很多种,以前我一直分不清各种之间的区别和Qt相应的处理机制,后来遇到一些实际的问题,然后再加上查阅源码和资料,总算弄明白一些事情,但是本文仅仅是个人理解,如有错误之处请告诉我,大家一起进步。

 

     图片是一种资源,而在Qt中,对于资源的使用是有其独特的方式的!

     ①:一般来说:资源在内存中是用资源对象树来表示的,该树在程序启动时创建。

     ②:而对于资源而言:我们都是需要先将其加入到这棵树中才能加载到内存中并被程序使用!!

     ③:而将一个图片资源放到程序的资源对象树中是用函数QResource::registerResource()来实现的。亦即:要将资源向这颗资源对象树进行注册,这样才对在系统中new创建这个资“叶子”。

        对于这一点我们可以直接查看该函数的源码:

 

        bool
       QResource::registerResource(const QString &rccFilename, const QString &resourceRoot)
       {
            QString r = qt_resource_fixResourceRoot(resourceRoot);
            if(!r.isEmpty() && r[0] != QLatin1Char('/'))

            {
                 qWarning("QDir::registerResource: Registering a resource [%s] must be rooted in an absolute path (start  with /) [%s]",
                 rccFilename.toLocal8Bit().data(), resourceRoot.toLocal8Bit().data());
                 return false;
            }

            QDynamicFileResourceRoot *root = new QDynamicFileResourceRoot(r);
            if(root->registerSelf(rccFilename))

            {
                 root->ref.ref();
                 QMutexLocker lock(resourceMutex());
                 resourceList()->append(root);
                 return true;
            }
           delete root;
           return false;
    }

   

       由上可见:主要就是先创建了一个资源内存对象,而后将其append到资源对象树上。

 

   ④:当我们不再使用某个图片资源时:当然希望其不再占用内存,此时需要释放delete它。这时要用QResource::unregisterResource()函数来进行反注册。此函数的作用就是在资源对象树中遍历找到代表该资源的节点,而后delete释放它。源码为:

 

    bool
    QResource::unregisterResource(const QString &rccFilename, const QString &resourceRoot)
    {
          QString r = qt_resource_fixResourceRoot(resourceRoot);

          QMutexLocker lock(resourceMutex());
          ResourceList *list = resourceList();
          for(int i = 0; i < list->size(); ++i)

          {
               QResourceRoot *res = list->at(i);
               if(res->type() == QResourceRoot::Resource_File)

               {
                    QDynamicFileResourceRoot *root = reinterpret_cast<QDynamicFileResourceRoot*>(res);
                     if(root->mappingFile() == rccFilename && root->mappingRoot() == r)

                     {
                         resourceList()->removeAt(i);
                          if(!root->ref.deref())

                          {
                              delete root;
                              return true;
                          }
                          return false;
                    }
               }
           }
           return false;
   }

 

 

    总起来说就是:一个程序所用的所有资源都是放到一颗资源对象树中的,当程序启动时该树便会自动创建,而当我们使用某个资源时:都需要实现将其向该树进行注册,当不需要时则需要进行反注册。

 

 

    ========================================================================

 

     下边说一下我常用的使用图片资源的方式,主要有三种:

 

      1:使用qrc资源文件来加载。

      对于这种方式:其是将所有的图片资源都转化成二进制数据,存放在一个静态数组中,而后放到应用程序中。所以:当程序执行时:所有图片都会一直在内存中,这杨虽然读取速度很快,但是很占用内存空间,对于一些内存有限的设备不是很适合。

 

      系统转换的主要步骤为:

      ①:当编译时,其会将我们写的 name.qrc文件转换生成一个qrc_name.cpp的资源文件,我们可以自己看下这个生成的cpp文件,发现其中就是主要有三个static const数组。

              qt_resource_data[]

              qt_resource_name[]

              qt_resource_struct[]

 

     这其中qt_resource_data[]中存放的就是图片的二进制数据。而后边的两个数组我们猜测是做了一个图片名字到上边数据的映射,方便系统找到data中的二进制数据。

 

       至于内部作用机制,有的资料上说是:当使用qrc资源文件时:系统会自动将所有的图片资源都向程序的资源对象树进行注册,并且当程序结束运行时再进行反注册。这也正好解释了为什么此种方法下图片资源会一直占用内存的原因。

 

       使用这种方法时:由于图片资源一直在内存中,避免了I/O操作,从而加快了读取速度。但是却是以消耗内存为代价的。我做过一个project,因为其中用了大量的图片,结果导致内存使用量超乎想象的大,后来就进行了优化,也就是用了下边提到的第二种方法。

 

 

     2:手动进行注册。

       第一种方法相当于静态加载,但很多情况下我们更希望是动态加载,亦即:用到哪个资源才将该资源加载进来,而不用的则不加载。

 上边第一种方法之 所以显示出静态加载的特性,这是由于系统一次性自动把所有图片资源都进行了注册,并且在程序运行过程中一直没有进行反注册才导致的。  如果我们可以自行决定:什么时候对那一部分图片资源进行注册?什么时候对哪一部分图片资源进行反注册。则显然我们可以手动控制整个资源在内存中的生存周 期!!

    

       这种方法的主要步骤为:

       ①:生成外部二进制资源文件。

       ②:在需要时将该资源向程序的资源对象树进行注册并使用。

       ③:在不需要时进行反注册。

      步骤①主要是用了Qt自带的一个工具:rcc.exe  (处于bin文件夹中)。这是Qt的一个资源编译器,其编译对象是qrc文件,而生成rcc二进制资源文件。

      那我们可以用它来执行命令 rcc -binary name.qrc -o name.rcc  来把qrc资源文件转成rcc二进制资源文件。

      而后在程序内部:当需要使用某一图片资源时:则直接调用

     QResource::registerResource(“name.rcc”)进行注册创建分配内存即可!  而不使用时候则调用反注册函数!!

 

     --》为了进行验证,我曾经测试了一个例子,主要思路就是:在一个工程中写了一个包含若干幅图片的qrc资源文件,将其转化成rcc二进制资源文件。   我在程序界面上摆放两个按钮button,  其中一个button的click事件响应槽负责调用QResource::registerResource()将这个二进制资源文件注册, 而另外一个button进行反注册。  然后跑一下这个程序,查看下其所占用的内存大小:

      

刚启动时:程序所占内存显示为:8940K

   

 

 

 

  而后按下第一个button进行注册,此时占用内存为:9276K

 

  最后点一下另外一个button,进行反注册后,其占用内存大小为:8948K

 

      

 

      由上测试可见:注册后才会让资源占用内存!!反注册后其会从内存中delete掉!!

 

     所以:这种方式算是动态加载,会少占用内存。但是如果图片过多的话,什么时候需要加载,什么时候需要去掉,这些逻辑就需要十分注意了。

 

 

    3:直接I/O读取。

     比如:  ptr->setStyleSheet("./bmp/name.png");

     这种方式我不怎么用,感觉I/O操作速度慢吧,所以一直没去深究。道理上边都有。

posted @ 2012-03-29 15:44 米米 阅读(1216) | 评论 (0)编辑 收藏

方法一:思路很好。值得学习
前两天有人问我关于如题所示的问题,具体就是说:现在他想做一个按钮,当click它时:只删除编辑框中的一个文字,而当常按press时:则连续的删除文字,此后一旦release,则立即停止删除问题。

      关于如何删除一个文字,这个很好实现,这里把重点放在:如何区分这两种状态上。

      我在实现时:只用了一个定时器。总体为:当第一次press时间达到0.5s时开始连续删除,如果按压的时间不足0.5s即release,则只删除一个文字;  而连续删除文字时:是每隔0.1s删除一个,一旦中途release了,则立即停止删除文字。

      代码如下,可以直接拿来用,当然,你需要自己手动实现删除编辑框中一个文字的函数DeleteOneCharacterInEditor()。

 

 timer1 = = new QTimer(this);

 

QObject::connect(timer1, SIGNAL(timeout ()),

this, SLOT(DeleteOneCharacter()));

QObject::connect(iDeleteButton, SIGNAL(pressed()),this , SLOT(PressDelete()));

QObject::connect(iDeleteButton, SIGNAL(released ()),this, SLOT(ReleaseDelete()));

 

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

void  test::PressDelete()  

{

      press = 1;

      timer1->setSingleShot(

true);

      timer1->start(500); 

}

 

void 

test::DeleteOneCharacter()

{

     if(mEditor)

     {

          DeleteOneCharacterInEditor();

     }

     press = 0; 

     timer1->start(100); 

}

 

void   test::ReleaseDelete()

    timer1->stop(); 

    if(press == 1)

    {

        if(mEditor)  

        {

            DeleteOneCharacterInEditor();

        }

}

方法2:
设置QPushButton的autoRepeat的属性,只要设为true就可以连续删除了,而且删除的时间间隔也可以设定。
posted @ 2012-03-29 15:18 米米 阅读(1167) | 评论 (0)编辑 收藏

在父widget上摆一个子widget后,当click子widget时:只会进入到子widget的相关事件处理函数中,比如进入到 mousePressEvent()中, 而不会进入到父widget的对应事件处理函数中。毕竟:click的是子widget,其遮挡住了父widget,从而父widget接收不到这个事 件。然而事实真的是这个样子吗?

     我做了一个测试: 在一个QWidget上建了一个QLabel。而后实现父QWidget的mousePressEvent(), 然后跟一下发现:当我click这个label时:居然能进入到父QWidget的mousePressEvent()中!但是如果把子改成 QPushButton则进入不了!


     咨询了一下别人,得到的答案是:如果子widget没有accept或ignore该事件,则该事件会被传递给其父亲。


   事实也确实如此:

    ①对于QLabel: 如果不重写mouse处理函数,也没有设置事件过滤器等操作的话,则相当于:其对mouse这个事件一直没有进行处理,那没有进行处理的话,相当于上边所说的情况,此时该事件会被传递给其parent。

    ②而对于QPushButton而言:当click它时:其会发射clicked()信号,其实这就相当于它对该事件的一个operator过程。所以:这里它accept该事件并进行了对应处理。从而:无法传递给其父窗口。



    那么:对于一个继承而来的类,只要我们重写实现了其各个事件处理函数,则对应的事件肯定无法传递给其父widget!  哪怕重写的该事件处理函数的函数体为空!


   如果是标准的控件对象,则其肯定没重写各个事件处理函数。那消息能不能传递到父widget中,则取决于中途有没有使用事件过滤器等将该信号拦截下来了。

posted @ 2012-03-29 15:09 米米 阅读(561) | 评论 (0)编辑 收藏

使用setStyleSheet来设置图形界面的外观:
QT Style Sheets是一个很有利的工具,允许定制窗口的外观,
此外还可以用子类QStyle来完成,他的语法很大比重来源于html的CSS,但是适用于窗口

概括:
Style Sheets是文字性的设定,对于整个应用程序可以使用QApplication::setStyleSheet() 或者对应一个窗口可以使用QWidget::setStyleSheet(),如果好几个样式表在不同的层次上设定,

QT将会集合所有的样式表来设定外观,这称作级串联
例如:下面的样式表指定所有的QLineEdit应该用黄色作为他们的背景颜色,所有的核对框应该用红色作为他们的文本颜色
QLineEdit { background: yellow }
QCheckBox { color: red }

对于这种定制,样式表比palette调色板更强大,例如使用QPalette::Button role来设定一个按钮为红色可能引起危险

对于单独使用QPalette很难完成的定制,样式表可以指定
样式表作用于当前窗口样式顶部,这意味这应用程序讲看起来尽可能的自然,但是任何样式表系统参数应该考虑,不像QPalette那样,样式表提供检查,如果你设定了一个按钮的背景颜色为红

色,你应该确定在所有的平台按钮将会有一个红色的背景,除此,Qt Designer提供样式表集成环境,使得在不同的窗口样式中更容易看到样式表的效果

此外,样式表可以用来为你的应用程序提供一个出众的外观,不需要使用子类QStyle,例如,可以指定任意的图片为单选按钮和核对按钮,来使它们出众,使用这个技术,也可以获得辅助的定

制,这将使用几个子类,例如指定style hint(样式暗示),可以参看例子 Style Sheet。

当样式表有效时候,使用QWidget::style()可以返回QStyle,

样式表语法:
样式表语法基本和HTML CSS语法一致。
样式表包含了样式规则序列,样式规则有一个<selector>和<declaration>组成,<selector>指定哪些窗口将会被这些规则影响,<declaration>指定哪些属性将会被设定在窗口上,例如
QPushButton{color:red}
在上面的,规则中,QPushButton是<selector>,{color:red}是<declaration>,这个规则指定QPushButton和他的子类将使用红色作为前景颜色,就是字体颜色,并且对大小写没有分别,对于

color,ColoR,COLOR是一样的。
几个<selector>可以同时被列出,使用逗号","来分开各个<selector>,例如:
QPushButton, QLineEdit, QComboBox { color: red }
<declaration>部分是一对 属性:值  对,用{}来括起来,使用分号来分开各个属性,例如
QPushButton { color: red; background-color: white }

可以参看Qt Style Sheets Reference来查看部件以及样式表的属性列表

关于样式表的级联属性
看下面代码的不同
 btn1->setStyleSheet("QPushButton{color:red}"); //设定前景颜色,就是字体颜色
 btn1->setStyleSheet("QPushButton{background:yellow}"); //设定背景颜色为红色

btn1->setStyleSheet("QPushButton{color:red;background:yellow}");
第一个代码只能显示黄色背景,第二个确实红色字体,黄色背景,
所以当设定一个部件时候,要在同一个>setStyleSheet()中完全写出来。

源代码示例:

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    this->setWindowFlags(this->windowFlags()&Qt::WindowMaximizeButtonHint&Qt::WindowMinimizeButtonHint);//为对话框添加上最大化和最小化按钮
//    layout=new QBoxLayout(this);
    layout1=new QGridLayout(this);
    btn1=new QPushButton(this);
    btn1->setStyleSheet("QPushButton{color:red;background:yellow}");//设定前景颜色,就是字体颜色
//    btn1->setStyleSheet("QPushButton{background:yellow}");
    btn1->setText("Button1");

    btn2=new QPushButton(this);
    btn2->setStyleSheet("QPushButton{color:red;background-color:#c89b64}");//使用rgb来设定背景颜色
    btn2->setText("Button2");

     btn3=new QPushButton(this);
     btn3->setStyleSheet("QPushButton{background-image:url(image/1.png);background-repeat: repeat-xy;background-position: center;background-attachment: fixed;background-attachment: fixed;background-attachment: fixed;;background-clip: padding}");
     //设定按钮的背景图片,background-repeat可以设定背景图片的重复规则,这里设定仅在xy方向都重复,所以图片会被重复一次
     //background-position用来设定图片的位置,是左(left)还是右(right),还是在中间(center),是上(top)还是底部(bottom)
     //background-attachment用来这定背景图片是否卷动或者和窗口大小相匹配,默认是卷动的
     btn3->setText("Button3");

     btn4=new QPushButton(this);
     btn4->setStyleSheet("QPushButton{border: 3px solid red;border-radius:8px}");//设定边框宽度以及颜色
     //可以使用border-top,border-right,border-bottom,border-left分别设定按钮的上下左右边框,
     //同样有border-left-color, border-left-style, border-left-width.等分别来设定他们的颜色,样式和宽度
     //border-image用来设定边框的背景图片。
     //border-radius用来设定边框的弧度。可以设定圆角的按钮
     btn4->setText("Button4");

    //字体设定
     //font-family来设定字体所属家族,
     //font-size来设定字体大小
     //font-style来设定字体样式
     //font-weight来设定字体深浅
     //height用来设定其高低
     //selection-color用来设定选中时候的颜色
     edit1=new QLineEdit(this);
     edit1->setStyleSheet("QLineEdit{font: bold italic large \"Times New Roman\";font-size:25px;color:#3764ff;height:50px;border:4px solid #9bc821;border-radius:15px;selection-color:pink}");

    //父窗口的设定
     //icon-size来设定图片大小
     this->setWindowIcon(QIcon("image/1.png"));
      this->setStyleSheet("QWidget{background:write url(image/2.png);icon-size:20px 5px}"); //设定整个对话框的背景颜色
//      this->setStyleSheet("QWidget{icon-size:20px 5px}");
    layout1->addWidget(btn1,0,0);
    layout1->addWidget(btn2,0,1);
    layout1->addWidget(btn3,1,0);
    layout1->addWidget(btn4,1,1);
     layout1->addWidget(edit1,2,0);
}

这里只给出来widget主窗口的cpp文件,运行得到的结果如下图

我们看到连粘贴 复制板都变成了使用样式表来设定的样式

关于使用样式表 setStyleSheet()) 来设定窗口样式的时候因该注意的事项,可以参看

http://blog.csdn.net/xie376450483/archive/2010/08/17/5818759.aspx

posted @ 2012-03-29 14:52 米米 阅读(936) | 评论 (0)编辑 收藏

原本的想法是在LineEdit的textEdited()事件触发时,如果输入了无效的目录名,则确认按钮无效,同时LineEdit的字的颜色为红色,想了老半天要如何解决这个问题,如何判断是否非法。都想到QString和字符串匹配上面去了。

       后来偶然搜索到一个帖子,提到了QRegExpValidator这个东西。研究了一下,利用一个正则表达式就可以很方便的限制用户的输入,代码如下:

Form的构造函数中的代码为:

QRegExp regExp("^[A-Za-z0-9_]+$");  //这里的意思是可以输入包含大小写字母,阿拉伯数字以及下划线
nameLineEdit->setValidator(new QRegExpValidator(regExp, this));

       后来把表达式成这样了:

QRegExp regExp("\w[A-Za-z0-9\-]*");

       这样的话,目录中除了第一个字符外可以包含小横线“-”了,哦也~~
Form类中的一个槽函数为:

void NewForm::on_nameLineEdit_textEdited()
{
    savePushBtn->setEnabled(nameLineEdit->hasAcceptableInput());
}

       发现,按钮状态触发的功能完成了,而在nameLineEdit中输入时,如果是星号啊,斜杠啊之类的直接就按了键也没反应,即不会显示到lineedit里面。这就无形之中将我那个想要把非法字符显示为红色的功能pass掉了,因为也没有必要了。

       无论如何解决了一个小问题却学到了很多。

1,用QRegExpValidator很有用。它将我要做的字符串匹配啊那些操作全部省略了,而对于正则表达式的学习还应该深入一下,因为我还没完全弄明白。Qt的资料真的很少,而里面内容很多,不可能一下子从头学,只能隧道式学习了。

2,用on_objectName_SignalName()这个函数命名的槽函数非常方便。它相当于自动会生成这段代码:

connect ( objectName, SIGNAL(SignalName), this, SLOT(on_objectName_SignalName()))

这也是以前跟黄老师一起讨论时,他老说on函数on函数的,我一时没会过意,现在我明白了。

       下面链接两个网页,我就不贴过来了,要查的话直接进去看吧:

QT4对话框快速设计:http://xuexg2000.blog.163.com/blog/static/139996409201032912432439/

(在这里我学会了on函数)

QT正则表达式:http://jesserei.blog.163.com/blog/static/121411689201011210846198/

(在这里学会如何设置合法字符)

posted @ 2012-03-29 14:07 米米 阅读(769) | 评论 (0)编辑 收藏

因为从QLineEdit中获取的字符串为QString类型, 但是想利用系统调用新建一个目录,然而,系统调用system(const char *)中必须为const char类型,如何把QString转换为char呢?下面的代码就可以实现。

QString copycommand = ...;
const char *c_copycommand = copycommand.toAscii().constData();

posted @ 2012-03-29 14:03 米米 阅读(1325) | 评论 (1)编辑 收藏

可以使不想要的按钮消失掉,但是frame的框框还存在。

setWindowFlags(windowFlags() &~ Qt::WindowMinMaxButtonsHint);

setWindowFlags(windowFlags() &~ Qt::WindowCloseButtonHint);   //Qt::WindowCloseButtonHint其实是一个值 0x00080000

       这里的“&~”是取反以后再按位与的意思,下面的“|”是按位或的意思。

       但是如果都不想要的时候,一起使用的时候就无效了。

setWindowFlags(windowFlags() &~ (Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint));

       偶然间发现了一个问题,我感觉是个bug,就是如果固定窗口的大小,哪么这个全部都屏蔽掉的方案就成功了。

setFixedSize(679, 423);

posted @ 2012-03-29 14:02 米米 阅读(1533) | 评论 (0)编辑 收藏

设置窗口居中显示

方法一:在窗口(QWidget类及派生类)的构造函数中添加如下代码:

#include <QDesktopWidget>

//.......
QDesktopWidget* desktop = QApplication::desktop(); // =qApp->desktop();也可以
move((desktop->width() - this->width())/2, (desktop->height() - this->height())/2);
//.......

重新编译后,该窗口启动时在屏幕居中的位置。

方法二:在调用show()函数后调用move()函数,j将窗口移动到屏幕中央。

#include <QDesktopWidget>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    w.move ((QApplication::desktop()->width() - w.width())/2,(QApplication::desktop()->height() - w.height())/2);
    return a.exec();
}

posted @ 2012-03-29 13:52 米米 阅读(1319) | 评论 (0)编辑 收藏

仅列出标题
共8页: 1 2 3 4 5 6 7 8