Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: stealth от Сентябрь 18, 2007, 11:32



Название: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Сентябрь 18, 2007, 11:32
Доброго дня!
Собственно сабж! Как делается на TableView такая штука, чтобы пользователь мог влючить или отключить показ колонок в таблице?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: Пантер от Сентябрь 18, 2007, 11:48
Конекти клик по HeaderView (ссылку на него можно достать из TableView) с функцией, которая будет создавать менюху. Потом hideColumn(int). В чем вообще проблема?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Сентябрь 18, 2007, 11:51
Как выловить клик по хедеру - это понятно, а вот как эту менюшку сделать такую? 


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: EhTemka от Сентябрь 18, 2007, 13:10
Зделай контекстное меню, так проще :)


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 17, 2007, 22:43
   Реализую функцию, которая бы генерировала менюшку.
   Вот произошел затык ;( Знаю, что передавать параметры в слоты нельзя, но специально пишу заведомо не рабочий код коннекта сигнала, т.к. логически понятно что я хочу получить.
   Как сделать эту конструкцию правильной?

   На входе функции model и tableView для неё.

 
Код:
   int i;
    for (i=0; i< model->columnCount(); i++) {

        QAction *action = new QAction(model->headerData(i, Qt::Horizontal).toString() , this);
        action->setCheckable(true);
        if (!ui.tableView->isColumnHidden(i))
            action->setChecked(true);
        // connect( action, SIGNAL( triggered() ),  ui.tableView, SLOT( hideColumn (i) ) ); - нужен рабочий аналог!!!!!!

ui.tableView->horizontalHeader()->addAction(action);

    }
    ui.tableView->horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);

Спасибо за советы!


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: Вячеслав от Октябрь 17, 2007, 22:59
QSignalMapper не катит ?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: Racheengel от Октябрь 18, 2007, 01:13
QActionGroup?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: Kainit от Октябрь 18, 2007, 09:09
В рамках приведённого фрагмента кода можно сделать не очень симпатично, но вполне разумно

т.е., немного схитрим в реализации (но гарантируя что сендерами сигналов будут только QAction-ы)

Код:
MyTableView::hideColumn () 
{
    QAction*action = qobject_cast<QAction*>sender();  // собственно, дальше можно и не писать, думаю что способ понятен

    if(!action ->isChecked ())
        HideColumn(action->text()); // это другой метод который предстоит реализовать, принимает строку имени колонки...
    else
       ShowColumn(action->text());
}

1. Я не предлагаю реализивывать скрытие и появление колонок 2-мя методами, разумнее сделать 1
2. Предлагаемый способ не очень красив, т.к. требует жесткого сендера...


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 18, 2007, 17:37
действительно для этой цели везде рекомендуют синалМаппер, но что-то у меня ничего не происходит, никаких сообщений тоже не вылазиет.
Код:
int i;
    QMenu *columnsMenu= new QMenu(tr("Колонки"));
    columnsMenu->setIcon(QIcon(":images/images/configure.png"));
    QSignalMapper *signalMapper;
    signalMapper = new QSignalMapper(this);

    for (i=0; i< modelNedw->columnCount(); i++) {

        QAction *action = new QAction(modelNedw->headerData(i, Qt::Horizontal).toString() , this);
        action->setCheckable(true);
        if (!ui.tableView->isColumnHidden(i))
            action->setChecked(true);
        connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
        signalMapper->setMapping(action, ui.tableView->isColumnHidden(i));

        connect(signalMapper, SIGNAL(mapped(int)),
                ui.tableView, SLOT(hideColumn(int)));
        columnsMenu->addAction(action);

    }
    QMenu *headerMenu= new QMenu;
    ui.tableView->horizontalHeader()->addAction(headerMenu->addMenu(columnsMenu));
    ui.tableView->horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);
Что может быть не так?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: Вячеслав от Октябрь 19, 2007, 10:56
        signalMapper->setMapping(action, ui.tableView->isColumnHidden(i));
Что может быть не так?
Эт шо ?
Код:
void setMapping ( QObject * sender, int id ) 
void setMapping ( QObject * sender, const QString & text )
void setMapping ( QObject * sender, QWidget * widget )
void setMapping ( QObject * sender, QObject * object )
Таки может

signalMapper->setMapping(action, i); ?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 19, 2007, 19:05
Вячеслав, спасибо за помощь!
Действительно колонки стали убираться.
Но тут опять засада :) Убираться-то они убираются (через hideColumn), а ведь еще нужно чтобы появлялись... а это надо вызывать уже showColumn. Как же завязать bool значение triggered(bool) от action`a на скрытие и раскрытие ума не приложу

to Racheengel - а как этот ActionGroup может помочь?
to Kainit - переопределять ничего не хотелось бы, ведь нужно чтобы это была функция, которую можно будет прилепить к любому QTableView


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: ритт от Октябрь 19, 2007, 22:24
setColumnHidden(int, bool) не поможет?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 20, 2007, 09:59
Если бы знать еще как его прикрутить :)


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 22, 2007, 20:12
Насколько я заметил - ни в одной KDE`ной проге нет реализации такой вот с виду простой штуки. В Amarok например появляется пункт меню "Скрыть колонку" и "Показать меню -> [Список скрытых колонок]"
В konqueror примерно тоже самое, через отдельный диалог с ListWidget`ом. Вообщем везде жутко неудобно!
В виндовом Explorer однако такая штука есть и работает отлично... Обидно :(



Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: ритт от Октябрь 22, 2007, 22:55
у меня в проекте сейчас реализовано то, о чём ты говоришь. плюс данное меню с тиарОфф. всё красиво и юзабельно...пока кол-во столбцов не превышает определённый лимит = (высота экрана/высоту элемента меню) - что-то порядка двадцати - двадцати пяти пунктов меню. если превышает, вся юзабельность превращается в напряг, особенно при включенном тиарОфф!

решил избавиться от этой менюхи в пользу доклета с ЛистВиджетом.

если у тебя столбцов мало, проблемы нет.


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 23, 2007, 19:02
Не подскажешь как ты этого добился?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: ритт от Октябрь 23, 2007, 21:08
чего добился? дерева? или меню с тиарОфф'ом?

у тебя вьюха родная или унаследованная?


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 23, 2007, 22:28
я не особо понял, что такое ТиарОФФ? :)
Интересует как сделал выпадающее меню с чекбоксами, чтобы они отрабатывали скрытие и открытие - аналогично тому, как это в виндовом експлорере сделано (при обзоре файлов и нажатии правой кнопкой по заголовку).
А с listView впринципе всё понятно...
Вьюха стандартная.


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: fox от Октябрь 24, 2007, 13:46
Доброго дня!
Собственно сабж! Как делается на TableView такая штука, чтобы пользователь мог влючить или отключить показ колонок в таблице?
Делал подобную вещь но меню выпадала только при клике по последней колонке таблицы
Если такой вариант устроит приведу код :)


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: ритт от Октябрь 24, 2007, 17:07
Код:
...

void TableView::setModel(QAbstractItemModel* model)
{
QTableView::setModel(model);


QSignalMapper* signalMapper = new QSignalMapper(this);
for(int i = 0; i < model->columnCount(); i++)
{
QAction* action = new QAction(model->headerData(i, Qt::Horizontal).toString(), this);
action->setCheckable(true);
action->setChecked(!isColumnHidden(i));
action->setData(i);
connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
signalMapper->setMapping(action, action);

horizontalHeader()->addAction(action);
}
connect(signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(showHideColumnsMenuTriggered(QObject*)));

horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);
}

...

void TableView::showHideColumnsMenuTriggered(QAction* action)
{
setColumnHidden(action->data().toInt(), !action->isChecked());
}

//данный слот для совместимости с сигналмаппером
void TableView::showHideColumnsMenuTriggered(QObject* obj)
{
QAction* action = qobject_cast<QAction*>(obj);
if(action)
showHideColumnsMenuTriggered(action);
}

...

5 рублей (или пИво)


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 24, 2007, 18:10
хер, с меня теперь точно 5 рублей или пиво! :)
Спасибо за действительно рабочий вариант этой штуки.
Но опять же это нужно наследовать TableView, а я, как писал выше, добиваюсь сделать функцию, которая бы возвращала QMenu (получая на входе модель и вью), который уже вешается на любой TableView. Наследоваться не всегда есть возможность - например при использовании форм, сделанных в QtDesigner.

Радует, конечно, create more, но еще хотелось бы и code less :)

to fox - приведи пожалуйста, чем больше вариантов, тем тема будет больше раскрыта!


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: fox от Октябрь 24, 2007, 18:37
to fox - приведи пожалуйста, чем больше вариантов, тем тема будет больше раскрыта!
Вообщем хотел сделать почти то же самое только для управления показом/скрытием колонок использовал отдельную колонку
По умолчанию последние где в заголовке нет текста только иконка

Соответственно для начала сигнал
Код:
  QHeaderView * head = horizontalHeader();
  connect(head, SIGNAL(sectionClicked(int)), this, SLOT(sectionClicked(int)));

а уже в обработчике проверка на то что клацнули на нужную мне колонку

Код:
  if(logicalIndex == Observer::MenuTerminalSection){
    QMenu menuSection(tr("Columns"), this);
    QHeaderView * head = horizontalHeader();
    int c = head->count();
    for(int i=0;i<c;++i){
      if(i == Observer::MenuTerminalSection){
        continue;
      }
      QAction * action = menuSection.addAction(model()->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
      action->setCheckable(true);
      action->setChecked(!head->isSectionHidden(i));
      action->setData(i);
    }
    QAction * action = menuSection.exec(QCursor::pos());
    if(action){
      int index = action->data().toInt();
      head->setSectionHidden(index, !action->isChecked());
      if(action->isChecked()) resizeColumnToContents(index);
    }
  }


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: ритт от Октябрь 24, 2007, 19:05
стэлз, смотри код внимательно - все используемые методы публичные. код можно использовать как внутри вьюхи, так и снаружи


Название: Re: Выпадающее меню на HeaderView с перечнем чекбоксов с названиями колонок
Отправлено: stealth от Октябрь 25, 2007, 21:50
to fox - хороший вариант, особенно хорошо, что достаточно просто реализуется
to xep - спасибо! угу, чёт я название класса просто увидел TableView и подумал, что ты его наследуешь от QTableView.
Всё заработало!

Вот что получилось в итоге (по большей части код от "xep" :) ):
Код:
//
//service.cpp
//
#include "service.h"
#include <QMessageBox>

QMenu *MenuForHeaderView::createMenu(QWidget *parent, QSqlRelationalTableModel *model, QTableView *view) {

    QMenu *columnsMenu= new QMenu(tr("Колонки"));
    columnsMenu->setIcon(QIcon(":images/images/configure.png"));

    QSignalMapper* signalMapper = new QSignalMapper(parent);

    for (int i = 0; i < model->columnCount(); i++) {
        QAction* action = new QAction(model->headerData(i, Qt::Horizontal).toString(), view);
        action->setCheckable(true);
        action->setChecked(!view->isColumnHidden(i));
        action->setData(i);
        signalMapper->setMapping(action, action);
        connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
        columnsMenu->addAction(action);
    }
    connect(signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(showHideColumnsMenuTriggered(QObject*)));
    v = new QTableView;
    v=view;

    return columnsMenu;
}

void MenuForHeaderView::showHideColumnsMenuTriggered(QAction* action) {
    v->setColumnHidden(action->data().toInt(), !action->isChecked());
    v->resizeColumnsToContents();
}

//данный слот для совместимости с сигналмаппером
void MenuForHeaderView::showHideColumnsMenuTriggered(QObject* obj) {
    QAction* action = qobject_cast<QAction*>(obj);
    if (action)
        showHideColumnsMenuTriggered(action);
}



Заголовочный файл
Код:
//
//service.h
//
#ifndef __SERVICE_H__
#define __SERVICE_H__
#include <QtGui>
#include <QtSql>

class MenuForHeaderView:public QObject {
    Q_OBJECT
public:
MenuForHeaderView(QObject *parent = 0): QObject(parent) {}

    QTableView *v;
    QMenu *createMenu(QWidget *parent=0, QSqlRelationalTableModel *model=0, QTableView *view=0);
public slots:
    void showHideColumnsMenuTriggered(QAction* action);
    void showHideColumnsMenuTriggered(QObject* obj);

};
#endif // __SERVICE_H__


А так вот использовать в программе:
Код:
...
//соответсвенно
//QSqlRelationalTableModel *model, QTableView *tableView

    MenuForHeaderView *mm = new MenuForHeaderView(this);
    QMenu *headerMenu= new QMenu;
    tableView->horizontalHeader()->addAction(headerMenu->addMenu(mm->createMenu(this, model, View) ));
    tableView->horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);
...

Большое спасибо всем, кто принял участие в данном обсуждении!