На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела *nix / gcc / Eclipse / Qt / wxWidgets / GTK+
  • При создании темы ОБЯЗАТЕЛЬНО указывайте версию тулкита / библиотеки / компилятора.
  • Перед тем как задать вопрос, сформулируйте его правильно, чтобы вас могли понять.
  • Нарушение Правил может повлечь наказание со стороны модераторов.


Полезные ссылки:
user posted image Boost по-русски
user posted image Qt по-русски
Модераторы: archimed7592
  
> QTableWidget: как перейти от выделения ячейки к выделению строки? , Win7, Qt Creator 5.0.2
    Есть таблица QTableWidget, в которой изначально поставлено выделение строк: QAbstractItemView::SelectRows.
    Есть кнопка по которой, по которой редактирую содержимое ячеек текущей строки, устанавливая QAbstractItemView::SelectItems.
    После редакции перехожу на другую строку таблицы и хочу чтобы при этом выделение сразу вернулось к SelectRows. Но сразу этого не получается, нужно дополнительно кликнуть по таблице ещё раз.
    Как сделать, чтобы сразу?
    ExpandedWrap disabled
      void MainWindow::on_btnEdit_clicked()
      {
          ui->tabW->clearSelection();
          ui->table->editItem(ui->table->item(ui->table->currentRow(), 1));
      //    ui->table->setSelectionMode(QAbstractItemView::SingleSelection);   // ничего не даёт
          ui->table->setSelectionBehavior(QAbstractItemView::SelectItems);
      }
       
      ...
       
      void MainWindow::on_table_currentCellChanged(int curRow, int curCol, int prevRow, int prevCol)
      {
       
          if (curRow != prevRow)
          {
      //        ui->table->clearSelection();
              ui->table->setEditTriggers( QAbstractItemView::NoEditTriggers );
      //        ui->table->setSelectionMode(QAbstractItemView::MultiSelection);
              ui->table->setSelectionBehavior(QAbstractItemView::SelectRows);
      //        ui->table->setRangeSelected(QTableWidgetSelectionRange(curRow, 0, curRow, ui->table->columnCount()-1), true);  // ничего не даёт
      }
      Привет, бро!

      Твоим вопросом пока не занимаюсь, но хочу дать тебе парочку советов. Которые как армейский Устав, "писаны кровью" (читай - временем на разборки):

      1. Прямо сейчас забудь про компоненты Qt, которые заканчиваются на *Widget. Вместо них пользуй *View. В твоем случае это QTableView - они более конфигурабельны. Виджеты - они для студентов, домохозяек и homeless людей.
      2. Если беда с кликами или клавой - она не беда, просто реализуй соответствующие обработчики, и смотри уже в них что и когда происходит
        Цитата Majestio @
        Вместо них пользуй *View.
        Т.е. не пользоваться дизайнером? Но это упрощает работу, тем более, если использовать свой класс на базе QTableWidget.
          Цитата vlad2 @
          Т.е. не пользоваться дизайнером?

          Забудь про дизайнер!!! Это - зло. Все контролы и их размещение нужно делать руками, вот это - по фэншую!
            Цитата vlad2 @
            Но это упрощает работу

            Оно упрощает работу ... на первый взгляд, когда ты создаешь "тупые и статические" формы. Но, как-только ты решишь разнообразить свой интерфейс - ты получишь кучу гемора от декларативных объявлений. Я тебе не советую "с потолка", я сам к этому пришел путем проб и ошибок. Программно создавать интерфейс на первый взгляд сложно. Но потом, когда это уже будет твоей практикой, я тебя уверяю - ты программно напишешь интерфейс кодом гораздо быстрее гвно-кликов в UI-дизайнере. Но у тебя есть варик - "пройди мой путь", если просто не доверяешь. Как говорят: "нет преграды патриотам" :lol:
              Majestio, спасибо. Если бы начинал программировать, то, наверное, воспользовался советом. Но мой стаж уже не 10 лет и даже не 20).
              Сейчас же меня интересует ответ на вопрос, поставленный в первом посте.
                Цитата vlad2 @
                Сейчас же меня интересует ответ на вопрос, поставленный в первом посте.

                Без синтетического примера сложно дать на 100% правильный ответ. Проверь вот такую связку в on_table_currentCellChanged:

                ExpandedWrap disabled
                  ui->table->clearSelection();
                  ui->table->selectRow(curRow);

                И еще, я думаю, что проверка if (curRow != prevRow) лишняя. Представь, ты редактируешь ячейку в строке, потом просто кликаешь на соседнюю ячейку этой же строки. По идее должно отработать ровно так же если бы ты кликал на ячейку другой строки?
                  Цитата Majestio @
                  Проверь вот такую связку
                  Проверял - до того, как написать и сейчас - не работает.
                  Т.е. мне надо, чтобы при редакции строки выделялась лишь текущая ячейка, а не вся строка, поэтому перед редакцией устанавливаю опцию QAbstractItemView::SelectItems. Но как только перехожу на другую строку, возможность редактирования пропадает (это работает) и сразу выделяется строка - устанавливаю опцию QAbstractItemView::SelectRows (для этого мне и нужна проверка if (curRow != prevRow)
                  Получается же, что при переходе на другую строку, остаётся выделенной только ячейка, куда кликнул, а чтобы выделилась строка, нужно дополнительно кликнуть ещё раз - куда угодно. Ну некрасиво).
                    Все-таки без какого-то, хотя бы минимального синтетического примера, трудно что-то говорить. Завершение редактирования обычно отлавливают двумя сигналами:

                    ExpandedWrap disabled
                      // Пример использования сигнала itemChanged
                      connect(tableWidget, &QTableWidget::itemChanged, [=](QTableWidgetItem* item) {
                          // Обработка события завершения редактирования ячейки
                      });
                       
                      // Пример использования сигнала cellChanged
                      connect(tableWidget, &QTableWidget::cellChanged, [=](int row, int column) {
                          // Обработка события завершения редактирования ячейки
                      });

                    Но не факт, что тебе это сможет помочь, т.к. ты манипулируешь двумя разными видами выделения. В этом случае, мне почему-то кажется, что нужно "спуститься вниз по иерархии" сигналов. А именно обрабатывать "сырой" клик на таблицу. И в нем уже обрабатывать начало редактирования, завершение редактирования, очередное выделение. Т.е. всё, что автоматом реализовано в QTableWidget в плане редактирования ячеек - тебе нужно будет переписать под себя руками. А на встроенные механизмы не надеяться.

                    Я бы попробовал убедиться в этом следующим образом - код, который вызывается в on_table_currentCellChanged запускать не напрямую, а через лямбду в QTimer::singleShot, с задержкой, допустим в 3 сек. С выводом в qDebug(). И обратить внимание, как отработало, что именно происходило, не было ли такого, что код отработал, а потом остальная логика QTableWidget вернула предыдущие настройки выделения.
                      Majestio, окончание редактирования я делаю сам:
                      ExpandedWrap disabled
                            void MainWindow::on_table_currentCellChanged(int curRow, int curCol, int prevRow, int prevCol)
                            {
                            
                                if (curRow != prevRow)
                                {
                                    ui->table->closePersistentEditor(ui->table->item(curRow, curCol));
                                    ui->table->clearSelection();
                                    ui->table->setEditTriggers( QAbstractItemView::NoEditTriggers );
                                    ui->table->setSelectionBehavior(QAbstractItemView::SelectRows);
                                }
                            }
                      И здесь SelectRows восстанавливается, потому что при повторном клике, например, по той же ячейке, где нахожусь, строка сразу же принимает вид выделенной. Такое ощущение, что после setSelectionBehavior(QAbstractItemView::SelectRows) нужно перерисовать строку или таблицу. Но repaint() не помогает.
                        Хорошо, а если добавить в самом конце, в блоке if:

                        ExpandedWrap disabled
                          ui->table->setSelectionMode(QAbstractItemView::SingleSelection);
                          ui->table->selectRow(curRow);

                        Что-то изменится?
                          Цитата Majestio @
                          Что-то изменится?
                          Нет. Я и раньше проделывал все эти танцы с бубном, и сейчас попробовал.
                            Цитата vlad2 @
                            Нет. Я и раньше проделывал все эти танцы с бубном, и сейчас попробовал.

                            Можешь скинуть свой код, ну или его чаcть, где это работает (вернее - не работает)?
                              Цитата Majestio @
                              Можешь скинуть свой код
                              Позже, может, к вечеру.
                                Вот рабочий тестовый пример.
                                ExpandedWrap disabled
                                  //  mainwindow.h
                                   
                                  #ifndef MAINWINDOW_H
                                  #define MAINWINDOW_H
                                   
                                  #include <QDialog>
                                  #include <QMainWindow>
                                   
                                  namespace Ui {
                                  class MainWindow;
                                  }
                                   
                                  class MainWindow : public QDialog
                                  {
                                      Q_OBJECT
                                   
                                  public:
                                      explicit MainWindow(QWidget *parent = nullptr);
                                      ~MainWindow();
                                   
                                  private slots:
                                      void on_btnEdit_clicked();
                                   
                                      void on_table_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn);
                                   
                                  private:
                                      Ui::MainWindow *ui;
                                    int Mode;
                                  };
                                   
                                  #endif // MAINWINDOW_H
                                ExpandedWrap disabled
                                  //  mainwindow.cpp
                                   
                                  #include "mainwindow.h"
                                  #include "ui_mainwindow.h"
                                   
                                  MainWindow::MainWindow(QWidget *parent) :
                                      QDialog(parent),
                                      ui(new Ui::MainWindow)
                                  {
                                      ui->setupUi(this);
                                      ui->table->blockSignals(true);
                                      ui->table->setRowCount(0);
                                      ui->table->setRowCount(10);
                                   
                                      for (int k = 0; k < ui->table->rowCount(); ++k)
                                      {
                                        for (int i = 0; i < ui->table->columnCount(); ++i)
                                        {
                                          ui->table->setItem(k, i, new QTableWidgetItem(QString::number(((k + i) * (k - i)) / 0.27)));
                                        }
                                      }
                                      ui->table->blockSignals(false);
                                      Mode = 0;
                                  }
                                   
                                  MainWindow::~MainWindow()
                                  {
                                      delete ui;
                                  }
                                   
                                  void MainWindow::on_btnEdit_clicked()
                                  {
                                      ui->table->clearSelection();
                                      ui->table->setEditTriggers( QAbstractItemView::AllEditTriggers);
                                      ui->table->editItem(ui->table->item(ui->table->currentRow(), 1));
                                  //    ui->table->setSelectionMode(QAbstractItemView::SingleSelection);
                                      ui->table->setSelectionBehavior(QAbstractItemView::SelectItems);
                                      Mode = 1;
                                  }
                                  void MainWindow::on_table_currentCellChanged(int curRow, int curCol, int prevRow, int prevCol)
                                  {
                                      if (Mode && curRow != prevRow)
                                      {
                                          ui->table->blockSignals(true);
                                          ui->table->closePersistentEditor(ui->table->item(curRow, curCol));
                                          ui->table->setEditTriggers( QAbstractItemView::NoEditTriggers );
                                   
                                  //        ui->table->setSelectionMode(QAbstractItemView::MultiSelection);
                                          ui->table->setSelectionBehavior(QAbstractItemView::SelectRows);
                                          ui->table->selectRow(curRow);
                                   
                                  //        ui->table->setRangeSelected( QTableWidgetSelectionRange(ui->table->currentRow(), 0, ui->table->currentRow(), ui->table->columnCount()-1), true);
                                          Mode = 0;
                                          ui->table->blockSignals(false);
                                      }
                                  }
                                  Еще бы mainwindow.ui, без него как-то тоскливо ;)
                                    Цитата vlad2 @
                                    Majestio, спасибо. Если бы начинал программировать, то, наверное, воспользовался советом. Но мой стаж уже не 10 лет и даже не 20).
                                    Сейчас же меня интересует ответ на вопрос, поставленный в первом посте.

                                    В общем, не дождался я UI-файла, накидал тебе работающий проект. По идее, все как тебе нужно. По твоему коду, невзирая на твой громадный стаж программирования, могу сказать одно - учиться никогда не поздно. Особенно если громадный стаж не касается какого-то нового для тебя инструментария. Если более конкретно - не забывай, что фрэймворк Qt построен по принципу MVC. Не нужно загонять данные в представление, представление его должно само извлекать из модели. Представь, что у тебя таблица со стопицот миллионов записей. Во время отображения, скроллинга, перерисовки QTableWidget/QTableView сам запросит нужную порцию данных. А вот как и откуда получит эти данные модель - это уже её зона ответственности.

                                    В присоединенном примере я это тебе реализовал. Там данные хранятся в переменной типа QVector<QVector<QString>>, при изменении - тудаже и записываются. Кнопочка [Dump] на форме в лог пишет текущее содержимое этой переменной. Ну а по самому интерфейсу все упрощенно:
                                    • Двойной клик на ячейке включает режим ее редактирования
                                    • Если во время редактирования нажать ESC, произойдет выход из режима редактирования и возврат исходного содержимого
                                    • Если во время редактирования нажать Enter или кликнуть на другую ячейку, то произойдет выход из режима редактирования и новые данные сохранятся
                                    • Про кнопку Dump уже писал выше
                                    Проект собирал под Qt 5.15.13 и Qt 6.7.0 - везде полёт нормальный. В общем, качай и разбирайся, может чего и пригодится.

                                    Прикреплённый файлПрикреплённый файлTestEditWidget.src.7z (2,93 Кбайт, скачиваний: 6)

                                    P.S. Небольшое дополнение. Присоединенный пример - конечно не эталон. Там упущена одна важная деталь - разорвана "связь" между хранилищем данных (переменной) и моделью. По фэн-шую хранилище данных нужно обернуть классом, сделать ему геттеры и сеттеры, а также связать сигналами & слотами его с моделью. Тогда при любом изменении данных в хранилище - изменения автоматом улетят в модель, а оттуда уже в представление.
                                      Цитата Majestio @
                                      Еще бы mainwindow.ui
                                      Добавил.
                                      Цитата Majestio @
                                      В общем, не дождался я UI-файла, накидал тебе работающий проект
                                      Извини, был в отъезде. Спасибо за проект, будет полезен для изучения. В твоём примере нет перехода от SelectItems к SelectRows, о чём , собственно и был мой первый вопрос: как сделать, чтобы строка выделялась сразу после того, как в ходе выполнения кода встречается setSelectionBehavior(QAbstractItemView::SelectRows) или что-то надо ещё добавить. Если не менять выделение строки, то редактируемая строка выглядит примерно так, как в твоём примере, только остаётся выделенной, а не серой, как в примере (см. картинку). Видимо, в твоём примере фокус переходит на editor, а у меня - нет.
                                      Что касается данных для таблицы, то в реальных таблицах они разных типов и берутся из двоичных файлов, поэтому в качестве хранения использую контейнеры структур типа QList<...>. Твой пример пригодится для организации редактирования с откатами и подтверждениями. Ну и для понимания структуры программ в Qt.
                                      Прикреплённый файлПрикреплённый файлmainwindow.ui (6,63 Кбайт, скачиваний: 3)
                                      Прикреплённая картинка
                                      Прикреплённая картинка
                                      Сообщение отредактировано: vlad2 -
                                        Цитата vlad2 @
                                        В твоём примере нет перехода от SelectItems к SelectRows, о чём , собственно и был мой первый вопрос: как сделать, чтобы строка выделялась сразу после того, как в ходе выполнения кода встречается setSelectionBehavior(QAbstractItemView::SelectRows) или что-то надо ещё добавить. Если не менять выделение строки, то редактируемая строка выглядит примерно так, как в твоём примере, только остаётся выделенной, а не серой, как в примере (см. картинку). Видимо, в твоём примере фокус переходит на editor, а у меня - нет.

                                        Да, когда я делал свой пример, у меня была одна цель - продемонстрировать правильный вход и выход из режима редактирования. Чтобы не было необходимости дополнительного клика на таблице, как ты писал в ранних сообщениях. Однако, хочу заметить, ты хочешь несколько видоизменить функционал интерфейса. Но по стандартам проектирования GUI фокусом может обладать только один элемент! А ты пытаешься сделать фокусом и строку, и редактируемую ячейку. Твой подход в данном случае будет неправильным. Предлагаю не ломать стандартную логику фокусного выделения, а просто перекрасить то, что не устраивает - в моем случае "серое" выделение. Решение этого несложное, добавим немножко кода.

                                        В файле ItemEditDelegate.h добавим перекрытие метода initStyleOption, теперь серый цвет будет заменен синим:

                                        ExpandedWrap disabled
                                          #ifndef ITEMEDITDELEGATE_H
                                          #define ITEMEDITDELEGATE_H
                                           
                                          #include <QStyledItemDelegate>
                                           
                                          class ItemEditDelegate : public QStyledItemDelegate {
                                                  Q_OBJECT
                                           
                                              public:
                                                  explicit ItemEditDelegate(QObject *parent = nullptr);
                                                  QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
                                                  void initStyleOption(QStyleOptionViewItem *option, const QModelIndex& index) const override {
                                                      QStyledItemDelegate::initStyleOption(option, index);
                                                      if (option->state & QStyle::State_Selected) {
                                                          option->palette.setColor(QPalette::HighlightedText, QColor(Qt::white));
                                                          option->palette.setColor(QPalette::Highlight, QColor(Qt::blue));
                                                      }
                                                  }
                                           
                                              signals:
                                                  void cellEditingStarted(const QModelIndex& index) const;
                                                  void cellEditingFinished(const QModelIndex& index) const;
                                          };
                                           
                                          #endif // ITEMEDITDELEGATE_H

                                        Одно важное замечание - в моем дополнении "перекраска" проводится строго в синий цвет. Но народ достаточно часто меняет под себя темы оформления своего рабочего стола. И не у всех цвет выделения синий. Поэтому будет более правильно с перекрываемом методе сперва находить цвет фона и текста по системным метрикам. Конечно это платформо-зависимые шляпы, для Windows своё WinAPI, для Линукc/FreeBSD - API X11, для MacOSX - API XQuartz. В общем, если тебя этот вопрос волнует - это тебе домашнее задание :lol:
                                          Цитата Majestio @
                                          А ты пытаешься сделать фокусом и строку, и редактируемую ячейку.

                                          Вовсе нет). На приведенной выше картинке показано, как не надо. Видимо, плохо объяснил. На приложенной к этому посту картинке показал текущую ситуацию:
                                          A - допустим, редактирую 5-ю строку (здесь SelectItems);
                                          B - после клика по 2-й строке, неважно, в какой ячейке, редакция заканчивается и устанавливается SelectRows. Но мы видим, что, несмотря на это, строка не выделена. Чтобы строка выделилась, нужно ещё раз кликнуть по этой строке;
                                          C - такую картинку хочу получить сразу после клика по 2-й строке.
                                          Сообщение отредактировано: vlad2 -

                                          Прикреплённая картинка
                                          Прикреплённая картинка
                                            Ну ок, спорить нет желания :lol: См. мою последнюю правку - по идее то, что ты хотел бы видеть.
                                              Цитата Majestio @
                                              См. мою последнюю правку - по идее то, что ты хотел бы видеть.
                                              Хотел я А + С из предыдущего поста. Если это похоже на твой пример с правкой, то ок, тоже не люблю спорить).
                                              В любом случае - спасибо за помощь.
                                              1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                              0 пользователей:


                                              Рейтинг@Mail.ru
                                              [ Script execution time: 0,0717 ]   [ 22 queries used ]   [ Generated: 20.05.24, 00:15 GMT ]