Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: arhiv6 от Март 27, 2014, 07:04



Название: Контекстное меню на QTableWidgetItem
Отправлено: arhiv6 от Март 27, 2014, 07:04
Добрый день.
На форме есть таблица (QTableWidget). Хочу иметь контекстное меню на элементах QTableWidgetItem этой таблицы + при выборе action из этого контекстного меню что-нибудь делать с этим QTableWidgetItem, но не знаю, как это сделать правильно.

1) Первый вариант - контекстное меню работает на всей таблице, даже где нет  ячеек + при вызове actionSlot1() или actionSlot1() я не знаю, на какой ячейке было вызвано контекстное меню:
Код:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // создаю 4 ячейки
    ui->tableWidget->setColumnCount(4);
    ui->tableWidget->setRowCount(1);
    for (int i  = 0; i < 4; ++i)
        ui->tableWidget->setItem( 0, i, new QTableWidgetItem("Element"+QString::number(i)));

    ui->tableWidget->setSelectionMode(QAbstractItemView::NoSelection);
    ui->tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);

    QAction *action1 = new QAction("action1",this);
    QAction *action2 = new QAction("action2",this);

    ui->tableWidget->addAction(action1);
    ui->tableWidget->addAction(action2);

    ui->tableWidget->connect(action1, SIGNAL(triggered()), this, SLOT(actionSlot1()));
    ui->tableWidget->connect(action2, SIGNAL(triggered()), this, SLOT(actionSlot2()));
}

void MainWindow::actionSlot1()
{
    qDebug() << "set action1";
}

void MainWindow::actionSlot2()
{
    qDebug() << "set action2";
}

2) Второй вариант - контекстное меню работает только на ячейках таблицы, я знаю на какой ячейке вызвано контекстное меню, но при выборе из этого меню action - как правильно перейти в обработчик для этого action+передать туда указатель на QTableWidgetItem?
Код:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),  ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->tableWidget->setColumnCount(4);
    ui->tableWidget->setRowCount(1);
    for (int i  = 0; i < 4; ++i)
        ui->tableWidget->setItem( 0, i, new QTableWidgetItem("Element"+QString::number(i)));

    ui->tableWidget->setSelectionMode(QAbstractItemView::NoSelection);
    ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);

    QAction *action1 = new QAction("action1",this);
    QAction *action2 = new QAction("action2",this);

    contextMenu=new QMenu();
    contextMenu->addAction(action1);
    contextMenu->addAction(action2);

    connect(ui->tableWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(slotShowContextMenu(const QPoint &)));
}

void MainWindow::slotShowContextMenu(const QPoint &pos)
{
    QTableWidgetItem *item;
    item = ui->tableWidget->itemAt(pos);

    if(!item)
        return;
   
    contextMenu->exec(QCursor::pos());
    qDebug() << "item text" << item->text();

}


Название: Re: Контекстное меню на QTableWidgetItem
Отправлено: gil9red от Март 27, 2014, 08:59
При вызове контекстного меню проверяйте текущий элемент таблицы ( currentItem() вернет или указатель на выделенную ячейку, или 0 ), если он равен 0, то нет выделенной ячейки, если есть, то у вас есть указатель на нее :)


Название: Re: Контекстное меню на QTableWidgetItem
Отправлено: arhiv6 от Март 27, 2014, 09:32
Рассматривал такой вариант, но он не подходит. Ячейки могут занимать только часть таблицы. Если выделить ячейку, и после этого вызвать контекстное на свободном от ячеек пространстве, то выделение с ячейки не снимется и указатель в currentItem() вернет не 0. А по-хорошему контекстное меню вызваться не должно, т.к. щелчок был не на ячейке (как в варианте 2 первого поста).


Название: Re: Контекстное меню на QTableWidgetItem
Отправлено: AlexEx от Март 29, 2014, 21:53
Как вариант, в слоте slotShowContextMenu для каждого action'а меню можно через его метод setData привязать ссылку на QTableWidgetItem, желательно не напрямую через прямое преобразование указателя (QVariant не работает с указателями), а через какой-нибудь вспомогательный QMap.


Название: Re: Контекстное меню на QTableWidgetItem
Отправлено: gil9red от Март 29, 2014, 21:55
Как вариант, в слоте slotShowContextMenu для каждого action'а меню можно через его метод setData привязать ссылку на QTableWidgetItem, желательно не напрямую через прямое преобразование указателя (QVariant не работает с указателями), а через какой-нибудь вспомогательный QMap.
QVariant вообще-то работает с указателями :)

Регистрация своего типа:
http://qt-project.org/doc/qt-4.8/qmetatype.html#Q_DECLARE_METATYPE

Помещение своего типа:
http://qt-project.org/doc/qt-4.8/qvariant.html#setValue
или http://qt-project.org/doc/qt-4.8/qvariant.html#fromValue

Получение своего типа:
http://qt-project.org/doc/qt-4.8/qvariant.html#value


Название: Re: Контекстное меню на QTableWidgetItem
Отправлено: arhiv6 от Март 31, 2014, 16:03
Спасибо. Хватило передавать не указатель на QTableWidgetItem, а всего лишь номер столбца, поэтому не пришлось регистрировать свой тип. Сделал так:
Код:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),  ui(new Ui::MainWindow)
{
    ui->setupUi(this);

        // создаю 4 ячейки
        ui->tableWidget->setColumnCount(4);
        ui->tableWidget->setRowCount(1);
        for (int i  = 0; i < 4; ++i)
            ui->tableWidget->setItem( 0, i, new QTableWidgetItem("Element"+QString::number(i)));

        ui->tableWidget->setSelectionMode(QAbstractItemView::NoSelection);
        ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);

        action1 = new QAction("action1",this);
        action2 = new QAction("action2",this);

        contextMenu=new QMenu();
        contextMenu->addAction(action1);
        contextMenu->addAction(action2);

        connect(ui->tableWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(slotShowContextMenu(const QPoint &)));
        connect(action1, SIGNAL(triggered()), this, SLOT(actionSlot1()));
        connect(action2, SIGNAL(triggered()), this, SLOT(actionSlot2()));
}

void MainWindow::slotShowContextMenu(const QPoint &pos)
{
    QTableWidgetItem *item;
    item = ui->tableWidget->itemAt(pos);

    if(!item)
        return;

    for (int i = 0; i < contextMenu->actions().size(); i++)
        contextMenu->actions().at(i)->setData(QVariant(ui->tableWidget->column(item)));

    contextMenu->exec(QCursor::pos()); // обязательно в конце функции
}

void MainWindow::actionSlot1()
{
    QAction* action = qobject_cast< QAction* >( sender() );
    qDebug() << "action 2, column" << action->data().toInt();
}

void MainWindow::actionSlot2()
{
    QAction* action = qobject_cast< QAction* >( sender() );
    qDebug() << "action 2, column" << action->data().toInt();
}