Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt GUI _ Работа с QTabWidget

Автор: RazrFalcon 5.4.2011, 14:46

Как я понял работу:
создаем на форму QTabWidget;
затем создаем классы, наследники QWidget;
в этих классам создаем нужные нам элементы GUI;
в класс нашего главного окна добавляем что то в духе:

tabWidget = new QTabWidget;
tabWidget->addTab(new newTab(), tr("Tab"));
.
В итоге получаем по классу для каждого таба. Как я понял.

Проблема в том, что я не пойму, как теперь обратится к главному окну из класса-таба.
К примеру мне нужно изменить ячейку в таблице (2-й таб), а ввожу я в первом табе.
Ну или банально изменить размер окна из таба. Ведь setGeometgy вызваный из первого таба не повлияет на главное окно.

PS: табы только для примера, текущего, проблема больше в взаимосвязями с классами.


Пример:
есть 2-а класса. Главный: WallWindow, и класс таба: ListTab.
Что бы что то изменить в табе ListTab из WallWindow, я делаю следующие:
void WallWindow::something()
{
    //...
    ListTab my;
    my.startButton->setText("Start");
    //...
}
Это правильно?

Автор: Алексей1153 5.4.2011, 16:57

1) можно произвести свой класс от вкладки и там сохранять указатель на родителя нужного класса
tabWidget->addTab(new newTab(tabWidget), tr("Tab"));Language: cpp

2) сигналы и слоты

Автор: RazrFalcon 5.4.2011, 17:29

1) не понял
2) как тогда изменить иконку главного окна кнопкой находящейся в табе?

Автор: Алексей1153 5.4.2011, 18:16

1) произвести класс-вкладку от QWidget, в конструкторе принять указатель на QTabWidget-родитель. Когда нужно, просто вызываешь нужный метод по указателю

2) а как это обычно делается ? Также, только в слоте, а слот соединён с сигналом кнопки

Автор: RazrFalcon 5.4.2011, 19:57

А можно с примером кода. Так как я все равно не понял.

Автор: Алексей1153 5.4.2011, 20:03

нет, пример сейчас я писать не в состоянии. А первый пункт - это классика C++ , в любом учебнике но нему есть

Автор: RazrFalcon 11.4.2011, 13:22

Спрошу еще раз, у всех.
Как вызвать функцию, которая определена в другом классе?

Пример:
.h

Раскрывающийся текст
class ListTab : public QWidget
{
    Q_OBJECT

public:
    ListTab(QWidget *parent = 0);

public slots:
    QFileInfoList load_and_show();
};

class settingTab : public QWidget
{
    Q_OBJECT

public:
    settingTab(QWidget *parent = 0);
private slots:
    void on_addFolderButton_clicked();
};


Мне нужно вызвать load_and_show(); в void settingTab::on_addFolderButton_clicked(){}. Как?

Автор: wiz29 11.4.2011, 13:38

Цитата(RazrFalcon @ 11.4.2011, 14:22) *
Мне нужно вызвать load_and_show(); в void settingTab::on_addFolderButton_clicked(){}. Как?

Для этого нужно иметь экземпляр класса ListTab в settingTab и вызвать соответствующий метод экземпляра класса (ListTab::on_addFolderButton_clicked).

но на самом деле вопрос поставлен не вполне корректно.

Автор: RazrFalcon 11.4.2011, 13:39

А пример можно? Я ничего не понял.

Автор: wiz29 11.4.2011, 13:46

тут нужно четко понимать что ты хочешь сделать. и не путать класс с экземпляром класса... Если QFileInfoList load_and_show() имеет статическую природу, тогда объяви эту функцию как статическую, если же данная функция имеет не статическую природу , тогда, в любом случае, придется иметь экземпляр одного класса в описании другого и с этим ничего не поделать.

Цитата(RazrFalcon @ 11.4.2011, 14:39) *
А пример можно? Я ничего не понял.

Для того куска кода который приведен выше , это будет выглядеть так:
class ListTab : public QWidget
{
    Q_OBJECT

public:
    ListTab(QWidget *parent = 0);

public slots:
    QFileInfoList load_and_show();
};

class settingTab : public QWidget
{
    Q_OBJECT

public:
    settingTab(QWidget *parent = 0);
private slots:
    void on_addFolderButton_clicked()
    {
         if (m_pListTab)
         {
              m_pListTab->load_and_show();
         }
    }
private:

    ListTab* m_pListTab;
};

Детали инициализации я здесь пропущу.

Автор: RazrFalcon 11.4.2011, 14:04

Блин!
Оно и до этого работало. Программа падала именно в load_and_show(), а не при определении класса.
Осталось понять в чем проблема.

Автор: wiz29 11.4.2011, 14:09

вообще что то несвязное, код в студию. (весь)

Автор: RazrFalcon 11.4.2011, 14:20

Вот в чем проблема:

settingTab::settingTab(QWidget *parent) : QWidget(parent)
{
  settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,
                           "wallpapers-changer", "wallchanger");

  addFolderButton = new QPushButton("Add folder",this);
  connect(addFolderButton, SIGNAL(clicked()), this, SLOT(on_addFolderButton_clicked()));
}

void settingTab::on_addFolderButton_clicked()
{
  QString selectedDir = QFileDialog::getExistingDirectory(this,
                                                          "Open Image(s)",
                                                          "/media/data",
                                                          QFileDialog::ShowDirsOnly);
  folderListWidget->addItem(selectedDir);
  dirList.append(selectedDir);

  if (!dirList.isEmpty())
    settings->setValue("settings/dirList",dirList);

  if (!settings->value("settings/dirList").toStringList().isEmpty()) {
    m_pListTab->load_and_show();
  }
}

не создается файл конфигов, settings. А если закомментить m_pListTab->load_and_show(); - то создается. А load_and_show() как раз его и читает. И получается, что оно читает файл который не создался, и программа убивается.

Автор: wiz29 11.4.2011, 14:27

программа убивается на строке:

m_pListTab->load_and_show();
?

если это так, то покажи пожалуйста код где инициализируется объект m_pListTab.

Автор: RazrFalcon 11.4.2011, 14:32

Нет. При попытке прочесть QSettings в load_and_show();

Инициализация:

class settingTab : public QWidget
{
    Q_OBJECT

public:
    QSettings *settings;
    ...

private slots:
    void on_addFolderButton_clicked();

private:
    ListTab* m_pListTab;
};

Автор: wiz29 11.4.2011, 14:42

возможно кинуть код проекта архивом, или архивом целиком файлы с данными классами, просто отрывки не отражают всей картины.

Автор: RazrFalcon 11.4.2011, 14:47

Еще сырой.

 wall_new.zip ( 10.17 килобайт ) : 87
 

Автор: wiz29 11.4.2011, 15:02

Проблема банальна, у тебя не инициализирована m_pListTab, т.е. адрес этого объекта = мусор. Инициализируй его в конструкторе класса settingTab

просто разыменование "мусора" ведет к непредсказуемому результату. это и вызывало падения...

Автор: RazrFalcon 11.4.2011, 15:04

Так что ли?

m_pListTab = new ListTab;

Автор: wiz29 11.4.2011, 15:10

settingTab::settingTab(QWidget *parent) : QWidget(parent)
{
  m_pListTab = new ListTab(this);
  settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,
                           "wallpapers-changer", "wallchanger");

  picFolders = new QLabel("Pictures folders:",this);
  addFolderButton = new QPushButton("Add folder",this);
  connect(addFolderButton, SIGNAL(clicked()), this, SLOT(on_addFolderButton_clicked()));
  folderListWidget = new QListWidget(this);
  QGridLayout *my = new QGridLayout;

  //QStringList dirList;
  //dirList = new QStringList;
  dirList = settings->value("settings/dirList").toStringList();
  //dirList<<"/media/data/Additional/Pictures"<<"/media/data/Additional/Images";

  my->addWidget(picFolders,0,0,1,3);
  my->addWidget(folderListWidget,1,0,1,3);
  my->addWidget(addFolderButton,2,0);
  setLayout(my);

  for (int i=0; i<dirList.count(); ++i) {
    folderListWidget->addItem(dirList.at(i));
  }

  if (!dirList.isEmpty())
    settings->setValue("settings/dirList",dirList);
}


Совет: по максимому используй возможности QtDesigner для создания диалогов, будет менее мусорный и читабельный код. Просто не имеет смысла "ковыряться" с размещением и компоновкой элементов, там где это реально не нужно. Это тебе сэкономит кучу времени на более полезные задачи.

Автор: RazrFalcon 11.4.2011, 15:23

Я так делал. Но таблица в первом табе не заполняется.

На счет совета: я знаю, просто ради интереса хотелось и в этом разобраться. Понять как оно изнутри работает.

Автор: wiz29 11.4.2011, 15:36

Цитата(RazrFalcon @ 11.4.2011, 16:23) *
Я так делал. Но таблица в первом табе не заполняется.

На счет совета: я знаю, просто ради интереса хотелось и в этом разобраться. Понять как оно изнутри работает.

так твоя таблица должна быть связана с settingsTab?


если это так, тогда все просто

измени конструктор settingTab на settingTab(ListTab* pListTab, QWidget *parent = 0)
settingTab::settingTab(ListTab* pListTab, QWidget *parent) : QWidget(parent)
{
    m_pListTab = pListTab;
  settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,
                           "wallpapers-changer", "wallchanger");
...............
}

WallWindow::WallWindow()
{
........

  listTab = new ListTab;
  settTab = new settingTab(listTab);
........
}




Автор: RazrFalcon 11.4.2011, 15:46

Ура! Спасибо. Работает как надо.
Я бы сам не додумался до такого. Просто еще не разу с таким количеством классов не сталкивался.
Теперь по аналогии можно доделывать все что я хотел.

Автор: RazrFalcon 11.4.2011, 20:16

И снова эти табы!
Теперь проблема с Ui
.h

Раскрывающийся текст
#ifndef WALLWINDOW_H
#define WALLWINDOW_H

#include <QMainWindow>
#include "ui_wallwindow.h"

class WallWindow : public QMainWindow, private Ui::WallWindow
{
    Q_OBJECT

public:
    WallWindow(QWidget *parent = 0);
};

class ListTab : public QWidget, private Ui::WallWindow
{
    Q_OBJECT

public:
    ListTab(QWidget *parent = 0);

public slots:
};

class folderTab : public QWidget, private Ui::WallWindow
{
    Q_OBJECT

public:
    folderTab(QWidget *parent = 0);

public slots:
};

#endif // WALLWINDOW_H

.cpp
Раскрывающийся текст
#include <QtDebug>

#include "wallwindow.h"

WallWindow::WallWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setupUi(this);
    //QWidget *mainWidget = new QWidget;
    //mainWidget->setLayout(verticalLayout);
    //setCentralWidget(mainWidget);
    qDebug()<<gridLayout_2->rowCount();
    gridLayout_2->setAlignment(spinBox,Qt::AlignRight);
}

ListTab::ListTab(QWidget *parent) : QWidget(parent)
{
    //gridLayout_2->setAlignment(spinBox,Qt::AlignRight);
    //setLayout(gridLayout_2);
    //qDebug()<<gridLayout_2->rowCount();
    //gridLayout_2->itemAtPosition(0,5)->setAlignment(Qt::AlignRight);
}


Все что я делаю в ListTab::ListTab не на что не влияет. Даже qDebug() не обрабатывается!

Автор: wiz29 12.4.2011, 8:25

естественно не работает, потому что не правильно делаешь:) Выложи код если не трудно, посмотрю

Автор: RazrFalcon 12.4.2011, 12:59

Да знаю что не правильно. Тут то табы уже созданы. А если делать как я раньше делал, то нужно было их создавать.

 wall.zip ( 3.59 килобайт ) : 80
 

Автор: wiz29 12.4.2011, 13:31

Сделай проще архитектурно, у тебя есть один диалог с табом, причем табы не динамические.
Тут у тебя есть уже готовые объекты которыми будешь управлять из WallWindow.
ListTab и FolderTab у тебя вообще не используется, тк вся форма создается в дизайнере вместе с наполнением. У тебя есть доступ ко всем объектам табов по именам в любой части WallWindow, поэтому не стесняясь можно создавать нужные слоты в WallWindow и наполнять функциональностью.
P.S. не забывай нормально именовать объекты в QtDesigner, самому будет проще разбираться что к чему, тк имена переменных pushButton1, pushButton2 не информативны:)

class WallWindow : public QMainWindow, private Ui::WallWindow
{
    Q_OBJECT

public:
    WallWindow(QWidget *parent = 0);

private slots:

    void on_addFolderButton_clicked();
    void tableFill();
    int setImage();
    void processStart(QString path, QString arg);
    QList<int> createRandomNumberList();

    void startButton_clicked();
    void on_onlynames_checkBox_stateChanged(int );
    void on_timeBox_valueChanged(int );
    void addButton_clicked();
    void on_table_cellDoubleClicked(int row, int column);
    void on_table_cellClicked(int row, int column);
    void clearButton_clicked();
    void on_pos_comboBox_currentIndexChanged(QString name);
    void order_comboBox_currentIndexChanged(QString name);
    void config_save();
    void nextImage();
    void previousImage();
    void iconActivated(QSystemTrayIcon::ActivationReason reason);
};


Остальные классы тебе в данном случае не нужны

Автор: RazrFalcon 12.4.2011, 13:31

Да-да. Это просто тестовый проект.

То есть, как я понял, допклассы создавать не нужно. Можно все реализовывать через WallWindow?

Автор: wiz29 12.4.2011, 13:39

Цитата(RazrFalcon @ 12.4.2011, 14:31) *
То есть, как я понял, допклассы создавать не нужно. Можно все реализовывать через WallWindow?

Именно так и есть. Тебе доступны все объекты форм в WallWindow. не зависимо от того в каком из табов они расположены.

Автор: RazrFalcon 12.4.2011, 13:54

Тогда получается, что работать с дизайнером действительно проще ^_^

Автор: wiz29 12.4.2011, 14:56

Дизайнер избавляет от "груды" однотипного и рутинного кода, экономя на этом время.

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)