Results 1 to 9 of 9

Thread: Custom Widget - First Steps

  1. #1
    Join Date
    Jun 2008
    Posts
    29
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Custom Widget - First Steps

    Been trying to create a custom tab widget that will auto-fill itself with a user-definable number of Faders.. each fader being a custom widget composed of a few buttons and a slider. I'm not really sure how to get started at defining a custom widget though. I've read the docs concerning the "vcr" example, but I can't find the original sources for the example. They say:

    Qt Code:
    1. Vcr::Vcr( QWidget *parent, const char *name )
    2. : QWidget( parent, name )
    3. {
    4. QHBoxLayout *layout = new QHBoxLayout( this );
    5. layout->setMargin( 0 );
    6.  
    7. QPushButton *rewind = new QPushButton( QPixmap( rewind_xpm ), 0, this, "vcr_rewind" );
    8. layout->addWidget( rewind );
    To copy to clipboard, switch view to plain text mode 

    We create a QHBoxLayout in which we'll place the buttons. We've only shown the rewind button in the code above since all the others are identical except for the names of the buttons, pixmaps and signals. For each of the buttons we require we call the QPushButton constructor passing it the appropriate embedded pixmap. We then add it to the layout. Finally we connect the button's clicked() signal to the appropriate signal. Since the clicked() signals aren't specific to our widget we want to emit signals that reflect the widget's use. The rewind(), play(), etc. signals are meaningful in the context of our widget so we propagate each button's clicked() signal to the appropriate widget-specific signal.

    I dont understand, though, which part of that code composes the "signal" aspect.. as I see no "emit" or "connect" or anything of the sort.
    Could someone perhaps give me an example of a qpushbutton ("Foo"), that will cause the parent container to give a "button1-presseddown" signal when it is pressed? I dont need custom pixmaps or anything, I just need a way to get three or four widgets into one container, and to be able to receive signals from the container instead of the individual buttons.

    Thank you
    Last edited by jpn; 19th June 2008 at 04:35. Reason: changed [quote] to [code] tags

  2. #2
    Join Date
    Sep 2007
    Location
    Rome, GA
    Posts
    199
    Thanks
    14
    Thanked 41 Times in 35 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: Custom Widget - First Steps

    This code isn't quite as elaborate as it seems, it should give you all the information you need about how to pass around signals within an object. I added the handleClick() method to the class just so you can see how the parent signal buttonClicked() connects to a slot, normally handleClick() would live in some other object.

    Feel free to ask if you have any questions. You ought to be able to put this code into a qt app and step it through the debugger so you can see what is happening.

    The QSignalMapper is not necessary for your purposes I don't think, but its a common problem that comes up when you're writing code like this, with multiple buttons in a parent container all sending signals, so I gave you an example of that too.

    Qt Code:
    1. #include <QtGui/QApplication>
    2. #include "ParentSignals.h"
    3.  
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication a(argc, argv);
    7. ParentSignals parent_signals;
    8. parent_signals.show();
    9. return a.exec();
    10. }
    11.  
    12. #ifndef PARENTSIGNALS_H
    13. #define PARENTSIGNALS_H
    14.  
    15. #include <QtGui>
    16.  
    17. class ParentSignals : public QWidget
    18. {
    19. Q_OBJECT
    20.  
    21. public:
    22. ParentSignals(QWidget * parent = 0);
    23. virtual ~ParentSignals();
    24.  
    25. signals:
    26. void buttonClicked(int button);
    27.  
    28. public slots:
    29. void handleClick(int button);
    30.  
    31. private:
    32. QPushButton * button_one;
    33. QPushButton * button_two;
    34. QPushButton * button_three;
    35. QPushButton * button_four;
    36. QPushButton * button_five;
    37.  
    38. QSignalMapper * button_mapper;
    39. };
    40.  
    41. #endif // PARENTSIGNALS_H
    42.  
    43. #include "ParentSignals.h"
    44.  
    45. ParentSignals::ParentSignals(QWidget * parent) : QWidget(parent)
    46. {
    47. button_mapper = new QSignalMapper();
    48.  
    49. button_one = new QPushButton("One");
    50. connect(button_one, SIGNAL(clicked()), button_mapper, SLOT(map()));
    51. button_mapper->setMapping(button_one, 1);
    52.  
    53. button_two = new QPushButton("Two");
    54. connect(button_two, SIGNAL(clicked()), button_mapper, SLOT(map()));
    55. button_mapper->setMapping(button_two, 2);
    56.  
    57. button_three = new QPushButton("Three");
    58. connect(button_three, SIGNAL(clicked()), button_mapper, SLOT(map()));
    59. button_mapper->setMapping(button_three, 3);
    60.  
    61. button_four = new QPushButton("Four");
    62. connect(button_four, SIGNAL(clicked()), button_mapper, SLOT(map()));
    63. button_mapper->setMapping(button_four, 4);
    64.  
    65. button_five = new QPushButton("Five");
    66. connect(button_five, SIGNAL(clicked()), button_mapper, SLOT(map()));
    67. button_mapper->setMapping(button_five, 5);
    68.  
    69. connect(button_mapper, SIGNAL(mapped(int)), this, SIGNAL(buttonClicked(int)));
    70.  
    71. connect(this, SIGNAL(buttonClicked(int)), this, SLOT(handleClick(int)));
    72.  
    73. QHBoxLayout * layout = new QHBoxLayout();
    74. layout->addWidget(button_one);
    75. layout->addWidget(button_two);
    76. layout->addWidget(button_three);
    77. layout->addWidget(button_four);
    78. layout->addWidget(button_five);
    79.  
    80. this->setLayout(layout);
    81. }
    82.  
    83. ParentSignals::~ParentSignals()
    84. {
    85.  
    86. }
    87.  
    88. void ParentSignals::handleClick(int button)
    89. {
    90. //do something cool here
    91. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by JimDaniel; 19th June 2008 at 05:58.

  3. #3
    Join Date
    Jun 2008
    Posts
    29
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Custom Widget - First Steps

    Thank you so much, first of all. This was just what I needed. I do have one question though:

    I'm trying to add a QSlider, and set its min and max values. Based off the documentation, I took

    Qt Code:
    1. new QSlider ( int minValue, int maxValue, int pageStep, int value, Orientation orientation, QWidget * parent, const char * name = 0 )
    To copy to clipboard, switch view to plain text mode 

    and made it into

    Qt Code:
    1. new QSlider ( 0, 100, 10, 0, Qt::Vertical, QWidget * parent, const char * name = 0 )
    To copy to clipboard, switch view to plain text mode 

    But I cant figure out what to pass for "QWidget * parent, const char * name = 0". Everything I try returns errors.

    Any suggestions?

  4. #4
    Join Date
    Sep 2007
    Location
    Rome, GA
    Posts
    199
    Thanks
    14
    Thanked 41 Times in 35 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: Custom Widget - First Steps

    Looking at Qt Assistant for 4.4.0, I don't see a QSlider constructor that takes those parameters, so I'm not sure what version you're using.

    But assuming the parameter list is correct, your problem is that when you pass in arguments, you can't declare a QWidget like that, its asking for a specific instance of a QWidget - if this QSlider lives in your custom widget, then you would pass in "this."

    As for the const char * name - followed by = 0 in the parameter list makes it a default parameter, which means you don't have to pass in anything - if you don't pass in anything 0, or nothing, will be passed in - in this case. But again, you can't declare anything as the actual argument, a const char * is looking for something like "My Cool Slider."

    So in case you're confused, if this QSlider lives in your custom widget, you could do something like this, and it should work:

    Qt Code:
    1. new QSlider(0, 100, 10, 0, Qt::Vertical, this, "My Cool Slider");
    To copy to clipboard, switch view to plain text mode 

    But take another look at the documentation for QSlider, your profile says you are using Qt 4.

  5. #5
    Join Date
    Jun 2008
    Posts
    29
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Custom Widget - First Steps

    Seems like I was using the wrong version of the documentation, sorry about that. Got it working well now, I have one "submaster" widget with my three buttons, a slider, and a spinbox. I connected the slots between the slider and spinbox so that they display eachother's values.

    What I now need to do is create a tabwidget that can be filled automatically with these Submaster Widgets.. 18 to a tab. I'd like it so that when the user clicks "Button 1" in "Widget 2", the tab widget will emit something like "Widget2,Button1 pressed".

    Would the best way to do this be to make a QSignalMapper for each button (so all of the "Button1"s would go to one mapper), or should I have one QSignalMapper for each SubmasterWidget, which then goes into Another QSignalMapper for the TabWidget-- or is this even possible?

    Also: Is there anyway to pass a value through a signal mapper? I have a signal being emitted when my slider-value is changed, but I'm not quite sure how to process it.

    Thank you for your help!

  6. #6
    Join Date
    Sep 2007
    Location
    Rome, GA
    Posts
    199
    Thanks
    14
    Thanked 41 Times in 35 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: Custom Widget - First Steps

    This should get you started:

    Qt Code:
    1. #include <QtGui/QApplication>
    2. #include "TabWidget.h"
    3.  
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication a(argc, argv);
    7. TabWidget w;
    8. w.show();
    9. return a.exec();
    10. }
    11.  
    12. #include <QList>
    13. #include <QWidget>
    14.  
    15. class SubMaster;
    16.  
    17. class TabWidget : public QWidget
    18. {
    19. Q_OBJECT
    20.  
    21. public:
    22. TabWidget(QWidget * parent = 0);
    23. virtual ~TabWidget();
    24.  
    25. signals:
    26. void buttonOneClicked(int submaster);
    27. void buttonTwoClicked(int submaster);
    28. void buttonThreeClicked(int submaster);
    29.  
    30. void sliderValueChanged(int submaster, int value);
    31. void spinboxValueChanged(int submaster, int value);
    32.  
    33. public slots:
    34. void handleSliderValueChange(int submaster);
    35. void handleSpinboxValueChange(int submaster);
    36.  
    37. private:
    38. QList<SubMaster *> m_submasters;
    39. };
    40.  
    41. #endif // TABWIDGET_H
    42.  
    43. #include <QVBoxLayout>
    44. #include <QSignalMapper>
    45.  
    46. #include "TabWidget.h"
    47. #include "ParentSignals.h"
    48.  
    49. TabWidget::TabWidget(QWidget *parent) : QWidget(parent)
    50. {
    51. QVBoxLayout * layout = new QVBoxLayout();
    52.  
    53. QSignalMapper * buttonOneMapper = new QSignalMapper(this);
    54. QSignalMapper * buttonTwoMapper = new QSignalMapper(this);
    55. QSignalMapper * buttonThreeMapper = new QSignalMapper(this);
    56. QSignalMapper * sliderMapper = new QSignalMapper(this);
    57. QSignalMapper * spinboxMapper = new QSignalMapper(this);
    58.  
    59. for(int i = 0; i < 18; ++i)
    60. {
    61. SubMaster * sub_master = new SubMaster();
    62.  
    63. connect(sub_master, SIGNAL(buttonOneClicked()), buttonOneMapper, SLOT(map()));
    64. buttonOneMapper->setMapping(sub_master, i);
    65. connect(buttonOneMapper, SIGNAL(mapped(int)), this, SIGNAL(buttonOneClicked(int)));
    66.  
    67. connect(sub_master, SIGNAL(buttonTwoClicked()), buttonTwoMapper, SLOT(map()));
    68. buttonTwoMapper->setMapping(sub_master, i);
    69. connect(buttonTwoMapper, SIGNAL(mapped(int)), this, SIGNAL(buttonTwoClicked(int)));
    70.  
    71. connect(sub_master, SIGNAL(buttonThreeClicked()), buttonThreeMapper, SLOT(map()));
    72. buttonThreeMapper->setMapping(sub_master, i);
    73. connect(buttonThreeMapper, SIGNAL(mapped(int)), this, SIGNAL(buttonThreeClicked(int)));
    74.  
    75. connect(sub_master, SIGNAL(sliderValueChanged()), sliderMapper, SLOT(map()));
    76. sliderMapper->setMapping(sub_master, i);
    77. connect(sliderMapper, SIGNAL(mapped(int)), this, SLOT(handleSliderValueChange(int)));
    78.  
    79. connect(sub_master, SIGNAL(spinboxValueChanged()), spinboxMapper, SLOT(map()));
    80. spinboxMapper->setMapping(sub_master, i);
    81. connect(spinboxMapper, SIGNAL(mapped(int)), this, SLOT(handleSpinboxValueChange(int)));
    82.  
    83. layout->addWidget(sub_master);
    84.  
    85. m_submasters.push_back(sub_master);
    86. }
    87.  
    88. this->setLayout(layout);
    89. }
    90.  
    91. TabWidget::~TabWidget()
    92. {
    93.  
    94. }
    95.  
    96. void TabWidget::handleSliderValueChange(int submaster)
    97. {
    98. int slider_value = m_submasters.at(submaster)->currentSliderValue();
    99. emit sliderValueChanged(submaster, slider_value);
    100. }
    101.  
    102. void TabWidget::handleSpinboxValueChange(int submaster)
    103. {
    104. int spinbox_value = m_submasters.at(submaster)->currentSpinBoxValue();
    105. emit spinboxValueChanged(submaster, spinbox_value);
    106. }
    107.  
    108.  
    109. #ifndef SUBMASTER_H
    110. #define SUBMASTER_H
    111.  
    112. #include <QtGui>
    113. #include <QtCore>
    114.  
    115. class SubMaster : public QWidget
    116. {
    117. Q_OBJECT
    118.  
    119. public:
    120. SubMaster(QWidget * parent = 0);
    121. virtual ~SubMaster();
    122.  
    123. int currentSliderValue() { return slider->value(); }
    124. int currentSpinBoxValue() { return spin_box->value(); }
    125.  
    126. signals:
    127. void buttonOneClicked();
    128. void buttonTwoClicked();
    129. void buttonThreeClicked();
    130.  
    131. void sliderValueChanged();
    132. void spinboxValueChanged();
    133.  
    134. private:
    135. QPushButton * button_one;
    136. QPushButton * button_two;
    137. QPushButton * button_three;
    138.  
    139. QSlider * slider;
    140. QSpinBox * spin_box;
    141. };
    142.  
    143. #endif // SUBMASTER_H
    144.  
    145. #include "SubMaster.h"
    146.  
    147. SubMaster::SubMaster(QWidget * parent) : QWidget(parent)
    148. {
    149. button_one = new QPushButton("One");
    150. connect(button_one, SIGNAL(clicked()), this, SIGNAL(buttonOneClicked()));
    151.  
    152. button_two = new QPushButton("Two");
    153. connect(button_two, SIGNAL(clicked()), this, SIGNAL(buttonTwoClicked()));
    154.  
    155. button_three = new QPushButton("Three");
    156. connect(button_three, SIGNAL(clicked()), this, SIGNAL(buttonThreeClicked()));
    157.  
    158. slider = new QSlider();
    159. connect(slider, SIGNAL(valueChanged(int)), this, SIGNAL(sliderValueChanged()));
    160.  
    161. spin_box = new QSpinBox();
    162. connect(spin_box, SIGNAL(valueChanged(int)), this, SIGNAL(spinboxValueChanged()));
    163.  
    164. connect(slider, SIGNAL(valueChanged(int)), spin_box, SLOT(setValue(int)));
    165. connect(spin_box, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
    166.  
    167. QHBoxLayout * layout = new QHBoxLayout();
    168. layout->addWidget(button_one);
    169. layout->addWidget(button_two);
    170. layout->addWidget(button_three);
    171. layout->addWidget(slider);
    172. layout->addWidget(spin_box);
    173.  
    174. this->setLayout(layout);
    175. }
    176.  
    177. SubMaster::~SubMaster()
    178. {
    179. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by JimDaniel; 21st June 2008 at 17:39.

  7. #7
    Join Date
    Jun 2008
    Posts
    29
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Custom Widget - First Steps

    JimDaniel,

    Thank you again for all the help. I'm attaching a screenshot, so you can see that I'm not just copying your work.

    Everything has gone well so far, I've gotten the custom widget to run withing my existing program, and I've been able to make it look the same as the older individual widgets did. The problem I'm having now is regarding signals and slots.

    I have the master layout for the custom widget in TabWidget.h, as per your suggestions. However, in my "MainWindowImpl.cpp" file, where the rest of my slots are

    Qt Code:
    1. connect(TabWidget,SIGNAL(buttonOneClicked(int submaster,int)),this,SLOT(bumpUp1(int submaster,int)));
    To copy to clipboard, switch view to plain text mode 

    Returns an:

    error: expected primary-expression before ‘,’ token

    I've tried a bunch of different things-- I tried making an instance of the class, which didnt work, and I tried connecting directly to the individual submasters themselves, which didnt work.

    For example:

    Qt Code:
    1. TabWidget * tab_widget = new TabWidget();
    2. connect(tab_widget,SIGNAL(buttonOneClicked(int submaster,int)),this,SLOT(bumpUp1(int submaster,int)));
    To copy to clipboard, switch view to plain text mode 

    Builds, but on clicking the button, returns

    Object::connect: No such signal TabWidget::buttonOneClicked(int submaster,int)
    Object::connect: (receiver name: 'MainWindow')

    It occurred to me that all other widgets are referenced by name, and not by class.. is that the problem that I'm having? How would I go about attaching a name to this custom widget? Or is that not the problem at all?

    Thank you again for your assistance
    Attached Images Attached Images

  8. #8
    Join Date
    Sep 2007
    Location
    Rome, GA
    Posts
    199
    Thanks
    14
    Thanked 41 Times in 35 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: Custom Widget - First Steps

    Cool, app looks slick. How are you styling the GUI if you don't mind me asking?

    Your problem in this case is just that you can't have a descriptor for parameters in the connect:

    Qt Code:
    1. connect(tab_widget, SIGNAL(buttonOneClicked(int, int)), this, SLOT(bumpUp1(int, int)));
    To copy to clipboard, switch view to plain text mode 

  9. #9
    Join Date
    Jun 2008
    Posts
    29
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Custom Widget - First Steps

    Great, got it working beautifully now. I just styled it in QDesigner, and set every object to Inherit, aside from a few tweaks. I usually try to conform to UI guidelines, but since it's designed to be run in a dark room, a bright style wouldnt have really worked for me.

    Thanks for all of your help!

Similar Threads

  1. resizing events of a custom widget in a layout
    By Rooster in forum Qt Programming
    Replies: 7
    Last Post: 16th February 2008, 10:52
  2. Custom widget
    By zorro68 in forum Qt Programming
    Replies: 7
    Last Post: 28th January 2008, 14:06
  3. custom plug-in widget in another custom plug-in widget.
    By MrGarbage in forum Qt Programming
    Replies: 6
    Last Post: 27th August 2007, 15:38
  4. Simple custom widget won't size properly
    By MrGarbage in forum Qt Tools
    Replies: 2
    Last Post: 9th August 2007, 13:12
  5. Custom tab widget question
    By PrimeCP in forum Qt Programming
    Replies: 2
    Last Post: 7th August 2007, 11:17

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.