Russian Qt Forum

Qt => Вопросы новичков => Тема начата: kemosab от Октябрь 20, 2017, 20:42



Название: Передача параметра в слот
Отправлено: kemosab от Октябрь 20, 2017, 20:42
Столкнулся с проблемой. У меня есть 50+ объектов типа  QFrame, которым я сделал всплывающее меню по правому клику, так вот теперь нужно сделать обработчик нажатия. При нажатии должен меняться цвет у выбранного фрейма.

Проблема в том, что все QFrame, а точнее указатели на них у меня хранятся в QList, и при инициализации окна я добавляю им в цикле всплывающее окно и связываю нажатия с обработчиком, но не могу сделать так, чтобы обработчик был один на каждый цвет.
Думаю с кодом будет понятнее.

Код
C++ (Qt)
   for (int i = 0; i < 6; i++) {
       for (int j = 0; j < 3; j++) {
           for (int k = 0; k < 3; k++) {
               allAct[0][countAct] = new QAction("Белый", mainFrames[i][j][k]);
               allAct[1][countAct] = new QAction("Оранжевый", mainFrames[i][j][k]);
               allAct[2][countAct] = new QAction("Зеленый", mainFrames[i][j][k]);
               allAct[3][countAct] = new QAction("Красный", mainFrames[i][j][k]);
               allAct[4][countAct] = new QAction("Синий", mainFrames[i][j][k]);
               allAct[5][countAct] = new QAction("Желтый", mainFrames[i][j][k]);
               mainFrames[i][j][k]->addAction(allAct[0][countAct]);
               mainFrames[i][j][k]->addAction(allAct[1][countAct]);
               mainFrames[i][j][k]->addAction(allAct[2][countAct]);
               mainFrames[i][j][k]->addAction(allAct[3][countAct]);
               mainFrames[i][j][k]->addAction(allAct[4][countAct]);
               mainFrames[i][j][k]->addAction(allAct[5][countAct]);
               mainFrames[i][j][k]->setContextMenuPolicy(Qt::ActionsContextMenu);
               mainFrames[i][j][k]->connect(allAct[0][countAct], SIGNAL(triggered), mainFrames[i][j][k], SLOT(mainFrames[i][j][k]));
               connect(allAct[0][countAct], SIGNAL(triggered), this, SLOT(changeWhite(mainFrames[i][j][k])));
               connect(allAct[1][countAct], SIGNAL(triggered()), this, SLOT(changeOrange()));
               connect(allAct[2][countAct], SIGNAL(triggered()), this, SLOT(changeGreen()));
               connect(allAct[3][countAct], SIGNAL(triggered()), this, SLOT(changeRed()));
               connect(allAct[4][countAct], SIGNAL(triggered()), this, SLOT(changeBlue()));
               connect(allAct[5][countAct], SIGNAL(triggered()), this, SLOT(changeYellow()));
           }
       }
   }
}
// слот для обработки нажатия на пункт меню
void MainWindow::changeWhite(QFrame *frame1)
{
   frame1->setStyleSheet("background-color: white");
}

выглядит крайне массивно и некрасиво, есть ли более изящное решение и как вообще передать параметр в слот, если при connect это нельзя сделать. А использовать QSignalMapper для массива таких объектов не понимаю как.


Название: Re: Передача параметра в слот
Отправлено: Swa от Октябрь 20, 2017, 22:22
Можно сделать через setData примерно так. Компилятора под рукой нет, так что возможны ошибки.

Код:
{
QAction* act1 = new QAction("Белый", mainFrames[i][j][k]);
act1->setData( "white" );
connect(act1 , SIGNAL(triggered()), this, SLOT(changeColor()));

QAction* act2  = new QAction("Оранжевый", mainFrames[i][j][k]);
act2->setData( "orange" );
connect(act2 , SIGNAL(triggered()), this, SLOT(changeColor()));

QAction* act3  = new QAction("Зеленый", mainFrames[i][j][k]);
act3->setData( "green" );
connect(act3 , SIGNAL(triggered()), this, SLOT(changeColor()));

QAction* act4  = new QAction("Красный", mainFrames[i][j][k]);
act4->setData( "red" );
connect(act4 , SIGNAL(triggered()), this, SLOT(changeColor()));

QAction* act5  = new QAction("Синий", mainFrames[i][j][k]);
act5->setData( "blue" );
connect(act5 , SIGNAL(triggered()), this, SLOT(changeColor()));

QAction* act6  = new QAction("Желтый", mainFrames[i][j][k]);
act6->setData( "yellow" );
connect(act6 , SIGNAL(triggered()), this, SLOT(changeColor()));


mainFrames[i][j][k]->addAction(act1);
mainFrames[i][j][k]->addAction(act2);
mainFrames[i][j][k]->addAction(act3);
mainFrames[i][j][k]->addAction(act4);
mainFrames[i][j][k]->addAction(act5);
mainFrames[i][j][k]->addAction(act6);
mainFrames[i][j][k]->setContextMenuPolicy(Qt::ActionsContextMenu);
}

void MainWindow::changeColor() {
    // Находим action, который отправил сигнал
    QAction* action = qobject_cast<QAction*>(QObject::sender());
    // Находим заложенный в него цвет
    QString color = action->data().toString();
    // Находим виджет-родитель
    QFrame* frame = qobject_cast<QFrame*>(action->parent());
    // Устанавливаем стиль
    color = color.prepend("background-color: ");
    frame ->setStyleSheet(color);
}


Название: Re: Передача параметра в слот
Отправлено: deMax от Октябрь 21, 2017, 15:25
allAct[0][countAct] = new QAction("Белый", mainFrames[j][k]);
allAct[1][countAct] = new QAction("Оранжевый", mainFrames[j][k]);

можно заменить на
int n=0;
for(auto& str: {"белый","синий","зеленый","...","..."}) {
    auto &mainFrame = mainFrames[j][k];
    mainFrame->addAction(allAct[n][countAct]  = new QAction("Белый", mainFrame));
    ++n;
} // mainframe имхо тут 2 раза не нужен

слоты тоже можно засунуть в список
auto f = {&Test::a1, &Test::a2, &Test::a3};
только пока не смотрел как в коннекте получить конкретный?





Название: Re: Передача параметра в слот
Отправлено: MrDron от Октябрь 23, 2017, 12:32
mainwindow.h
Код
C++ (Qt)
   QList<QFrame*> listFrames;
   QMenu popupMenu;
   QFrame *activeFrame;

mainwindow.cpp
Код
C++ (Qt)
MainWindow::MainWindow() {
   auto listColors = QList<QPair<QString, QString> >()
           << qMakePair(QString("white"),  QString("Белый"))
           << qMakePair(QString("orange"), QString("Оранжевый"))
           << qMakePair(QString("green"),  QString("Зеленый"))
           << qMakePair(QString("red"),    QString("Красный"))
           << qMakePair(QString("blue"),   QString("Синий"))
           << qMakePair(QString("yellow"), QString("Желтый"));
 
   QList<QAction*> listActions;
   for (auto color : listColors) {
       QPixmap pixmap(16, 16);
       pixmap.fill(QColor(color.first));
       auto action = new QAction(QIcon(pixmap), color.second, this);
       action->setData(color.first);
       listActions << action;
       connect(action, &QAction::triggered, this, &MainWindow::changeColor);
   }
   this->popupMenu.addActions(listActions);
 
   for (auto frame : this->listFrames)
       frame->installEventFilter(this);
}
 
bool MainWindow::eventFilter(QObject *object, QEvent *event) {
   if (event->type() == QEvent::ContextMenu) {
       this->activeFrame = static_cast<QFrame*>(object);
       this->popupMenu.exec(QCursor::pos());
   }
   return QObject::eventFilter(object, event);
}
 
void MainWindow::changeColor() {
   activeFrame->setStyleSheet(QString("background-color: %1").arg(static_cast<QAction*>(sender())->data().toString()));
}