I'm trying to implement pinned menu items for use in a list of recently opened files. (For example, like Microsoft Office 2007 and 2010 do.) I'm almost there, but I haven't been able to properly align the pin images. What I need is something like putting a grid layout on the whole menu, but I don't think I can do that. Any suggestions? I've appended my pinmenu code and a test program.

Qt Code:
  1. // pinmenu.cpp
  2. #include "pinmenu.h"
  3.  
  4. PinMenu::PinMenu(const QString& title, int id, bool pinstate) : QWidgetAction(NULL)
  5. {
  6. pinmap = QPixmap(":/pin.png");
  7. unpinmap = QPixmap(":/unpin.png");
  8. pinWidget = new QWidget();
  9. pinLayout = new QHBoxLayout();
  10. pinLayout->setMargin(0);
  11. pinLayout->setContentsMargins(5, 3, 5, 3);
  12. pinTitle = new ClickableLabel(title);
  13.  
  14. // This ugly attempt to line up the pin icons will break if title is too long,
  15. // and it doesn't even succeed in lining up the icons very well.
  16. int pixelWidth = pinTitle->fontMetrics().boundingRect(pinTitle->text()).width();
  17. pinLayout->setSpacing(200 - pixelWidth);
  18.  
  19. pinLayout->addWidget(pinTitle);
  20. pinImage = new ClickableLabel();
  21. pinLayout->addWidget(pinImage);
  22. pinWidget->setLayout(pinLayout);
  23. setPinState(pinstate);
  24. setDefaultWidget(pinWidget);
  25. idno = id;
  26. connect(pinTitle, SIGNAL(clicked()), this, SLOT(slot_textClicked()));
  27. connect(pinImage, SIGNAL(clicked()), this, SLOT(slot_pinClicked()));
  28. }
  29.  
  30. PinMenu::~PinMenu()
  31. {
  32. delete pinLayout;
  33. delete pinWidget;
  34. }
  35.  
  36. bool PinMenu::isPinned()
  37. {
  38. return pinned;
  39. }
  40.  
  41. bool PinMenu::togglePin()
  42. {
  43. setPinState(!pinned);
  44. return pinned;
  45. }
  46.  
  47. void PinMenu::setPinState(bool pin)
  48. {
  49. pinned = pin;
  50. pinImage->setPixmap(pinned ? pinmap : unpinmap);
  51. }
  52.  
  53. void PinMenu::slot_textClicked()
  54. {
  55. emit signal_textClicked(idno);
  56. }
  57.  
  58. void PinMenu::slot_pinClicked()
  59. {
  60. togglePin();
  61. // Don't emit this signal - it closes the menu
  62. // emit signal_pinClicked(idno);
  63. }
To copy to clipboard, switch view to plain text mode 
Qt Code:
  1. // pinmenu.h
  2. #ifndef PINMENU_H
  3. #define PINMENU_H
  4.  
  5. #include <QWidgetAction>
  6. #include <QHBoxLayout>
  7. #include "clickablelabel.h"
  8.  
  9. class PinMenu : public QWidgetAction
  10. {
  11. Q_OBJECT
  12. public:
  13. PinMenu(const QString& title, int id, bool pinstate);
  14. ~PinMenu();
  15. bool isPinned();
  16. bool togglePin();
  17. void setPinState(bool pin);
  18.  
  19. private:
  20. int idno;
  21. bool pinned;
  22. ClickableLabel *pinImage;
  23. ClickableLabel *pinTitle;
  24. QPixmap pinmap;
  25. QPixmap unpinmap;
  26. QWidget *pinWidget;
  27. QHBoxLayout *pinLayout;
  28.  
  29. private slots:
  30. void slot_textClicked();
  31. void slot_pinClicked();
  32.  
  33. signals:
  34. void signal_textClicked(int);
  35. void signal_pinClicked(int);
  36. };
  37.  
  38. #endif // PINMENU_H
To copy to clipboard, switch view to plain text mode 
Qt Code:
  1. // main.cpp
  2. #include <QtGui/QApplication>
  3. #include "mainwindow.h"
  4.  
  5. int main(int argc, char *argv[])
  6. {
  7. QApplication a(argc, argv);
  8. MainWindow w(0);
  9. w.show();
  10. return a.exec();
  11. }
To copy to clipboard, switch view to plain text mode 
Qt Code:
  1. // mainwindow.cpp
  2. #include "mainwindow.h"
  3. #include "ui_mainwindow.h"
  4. #include "pinmenu.h"
  5.  
  6. #include <QMessageBox>
  7. #include <QHBoxLayout>
  8. #include <QLabel>
  9.  
  10. MainWindow::MainWindow(QWidget *parent)
  11. : QMainWindow(parent), ui(new Ui::MainWindow)
  12. {
  13. ui->setupUi(this);
  14.  
  15. QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
  16. // Avoid warning that open is not used in this test program
  17. // QAction *open = addMenuItem(fileMenu, tr("&Open"), SLOT(slot_open_clicked()));
  18. addMenuItem(fileMenu, tr("&Open"), SLOT(slot_open_clicked()));
  19. QMenu *openRecentFilesMenu = fileMenu->addMenu(tr("&Recently used files"));
  20. addMenuItem(fileMenu, tr("E&xit"), SLOT(slot_close_clicked()));
  21.  
  22. PinMenu *pinMenuAction1 = new PinMenu(tr("Short name"), 1, true);
  23. openRecentFilesMenu->addAction(pinMenuAction1);
  24. connect(pinMenuAction1, SIGNAL(signal_textClicked(int)), this, SLOT(slot_textClicked(int)));
  25. // connect(pinMenuAction1, SIGNAL(signal_pinClicked(int)), this, SLOT(slot_iconClicked(int)));
  26.  
  27. PinMenu *pinMenuAction2 = new PinMenu(tr("Long name to test alignment"), 2, false);
  28. openRecentFilesMenu->addAction(pinMenuAction2);
  29. connect(pinMenuAction2, SIGNAL(signal_textClicked(int)), this, SLOT(slot_textClicked(int)));
  30. // connect(pinMenuAction2, SIGNAL(signal_pinClicked(int)), this, SLOT(slot_iconClicked(int)));
  31. fileMenu->setLayout(new QGridLayout());
  32. }
  33.  
  34. MainWindow::~MainWindow()
  35. {
  36. delete ui;
  37. }
  38.  
  39. void MainWindow::slot_close_clicked()
  40. {
  41. close();
  42. }
  43.  
  44. void MainWindow::slot_open_clicked()
  45. {
  46. // Code here to open file
  47. }
  48.  
  49. void MainWindow::slot_textClicked(int id)
  50. {
  51. QMessageBox::information(this, "Info", tr("Text clicked, id = %1").arg(id));
  52. }
  53.  
  54. void MainWindow::slot_iconClicked(int id)
  55. {
  56. QMessageBox::information(this, "Info", tr("Icon clicked, id = %1").arg(id));
  57. }
  58.  
  59. QAction *MainWindow::addMenuItem(QMenu *whichMenu, QString menuText, const char *method)
  60. {
  61. QAction *openAction = new QAction(menuText, this);
  62. connect(openAction, SIGNAL(triggered()), this, method);
  63. whichMenu->addAction(openAction);
  64. return openAction;
  65. }
To copy to clipboard, switch view to plain text mode 
Qt Code:
  1. // mainwindow.h
  2. #ifndef MAINWINDOW_H
  3. #define MAINWINDOW_H
  4.  
  5. #include <QtGui/QMainWindow>
  6.  
  7. namespace Ui
  8. {
  9. class MainWindow;
  10. }
  11.  
  12. class MainWindow : public QMainWindow
  13. {
  14. Q_OBJECT
  15.  
  16. public:
  17. MainWindow(QWidget *parent = 0);
  18. ~MainWindow();
  19.  
  20. private:
  21. QAction *addMenuItem(QMenu *whichMenu, QString menuText, const char *method);
  22.  
  23. private slots:
  24. void slot_close_clicked();
  25. void slot_open_clicked();
  26. void slot_iconClicked(int id);
  27. void slot_textClicked(int id);
  28.  
  29. private:
  30. Ui::MainWindow *ui;
  31. };
  32.  
  33. #endif // MAINWINDOW_H
To copy to clipboard, switch view to plain text mode 
Qt Code:
  1. // clickablelabel.cpp
  2. #include "clickablelabel.h"
  3.  
  4. // This comes from http://qt-project.org/wiki/Make-a-QLabel-Clickable
  5. // License is Creative Commons Attribution-ShareAlike 2.5 Generic
  6.  
  7. ClickableLabel::ClickableLabel(const QString& text, QWidget *parent) :
  8. QLabel(parent)
  9. {
  10. this->setText(text);
  11. }
  12.  
  13. ClickableLabel::~ClickableLabel()
  14. {
  15. }
  16.  
  17. void ClickableLabel::mousePressEvent (QMouseEvent * /* event */)
  18. {
  19. emit clicked();
  20. }
To copy to clipboard, switch view to plain text mode 
Qt Code:
  1. // clickablelabel.h
  2. #ifndef CLICKABLELABEL_H
  3. #define CLICKABLELABEL_H
  4.  
  5. // This comes from http://qt-project.org/wiki/Make-a-QLabel-Clickable
  6. // License is Creative Commons Attribution-ShareAlike 2.5 Generic
  7.  
  8. #include <QLabel>
  9.  
  10. class ClickableLabel : public QLabel
  11. {
  12. Q_OBJECT
  13.  
  14. public:
  15. explicit ClickableLabel(const QString& text ="", QWidget *parent = 0);
  16. ~ClickableLabel();
  17.  
  18. signals:
  19. void clicked();
  20.  
  21. protected:
  22. void mousePressEvent(QMouseEvent *event) ;
  23. };
  24.  
  25. #endif // CLICKABLELABEL_H
To copy to clipboard, switch view to plain text mode