Reference to ui widgets from a subclass



  • I have a MainForm created by QtCreator, with a QTableView named tvMeresTabla. As I want to catch the table's selectionChanged event, I have made a class "Tabla" subclassed from QTableView.

    Tabla.h
    @
    class Tabla : public QTableView {
    Q_OBJECT;
    public:
    Tabla(QWidget* parent = NULL);
    QStandardItemModel *tbl;
    protected:
    virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
    };
    @

    Tabla.cpp
    @Tabla::Tabla(QWidget* parent) : QTableView(parent) {
    tbl= new QStandardItemModel(0,18) ;
    }

    void MainWindow::InitTabla() {
    ui->tvMeresTabla->setModel(ui->tvMeresTabla->tbl);
    }

    void Tabla::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
    QTableView::selectionChanged(selected, deselected); //system does the stuff
    QModelIndexList indexes= ui->tvMeresTabla->selectionModel()->selection().indexes(); //<<<<<<<<-----ERROR: ui not declared in thisscope

    ActiveWkSheet= indexes.at(0).data(Qt::DisplayRole).toInt(); //getting which table row is selected
    }
    @

    Everything works fine without the inner part of Tabla::selectionChanged(), but the above "indexes= ui->" part not compiles with the error "ui not declared in this scope".
    What is the proper syntax of a reference to UI widgets from a function within the "Tabla" scope/namespace?



  • At your example you don't need to use ui member of MainWindow at all, because you use it to invoke method of the same object you are in.
    @
    QModelIndexList indexes= selectionModel()->selection().indexes();
    @



  • Okay, wrong question:)) How can I reach other screen objects from within the Tabla::selectionChanged() ? (E.g. I have a QPushButton. "ui->myButton" won't work.)



  • you can't.

    Your selection changed method is part of Tabla which is a child object of the main window.
    There is no (normal) way to reach other children of the main window.

    The normal way for those things would be using signals of your view inside the main window sand act from there.

    What I don't understand: why did you subclass QTableView?

    Signals would do it and be the normal Qt way....



  • In this case I think it will be wrong by design. One object should be aware of internls of another object. It is better to provide some interface to work with needed internals (for example you can add method changeOkButtonText() to change text on some button of your window). If you want to provide full access to ui member of MainWindow to other classes you can move it from private to public section in MainWindow header.



  • [quote author="Gerolf" date="1297105341"]The normal way for those things would be using signals of your view inside the main window and act from there.

    What I don't understand: why did you subclass QTableView?

    Signals would do it and be the normal Qt way....[/quote]

    The case:
    I have worksheets to handle. The same sheets can be displayed on 3 tabs of a tabwidget. One tab is for displaying a single wksheet on several QLineEdits, the other tab is full of a grid of a QTableView, the 3rd is a grapical representation (QGraphView). There is a quite "global" int SelectedWorkSheet.

    When I choose a row on QTableView (=select a single worksheet), I want this variable to be set.
    If user clicks on a different tab, the selected worksheet will be drawn on the new tab.
    For this I need a signal emitted when row selection changed in tableview, but QTableView doesn't emit signal if selected row changes.
    I think subclassing is the way to emit a signal which is not emitted by default.

    QTableView has a virtual selectionChanged(). I subclass QTableView to MyTableView.
    Original UI's part is "Promote"d to MyTableView.
    In MyTableView's selectionChanged() I can emit() a signal, that can be connected to a slot function on MainWindow, which will set my SelectedWorkSheet.

    I know it's un-stylish, but I could set the SelectedWorkSheet variable in the selectionChanged() event handler directly, if it was visible in that scope.
    And is there other way than subclassing to make a virtual function of a class implemented?

    Thanks in advance for helping me to understand the "soul" of Qt



  • I would suggest:

    • create a manager class, that controls the ui widgets
    • connect the signals of the ui components (eg. "QItemSelectionModel::selectionChanged() ":http://doc.qt.nokia.com/latest/qitemselectionmodel.html#selectionChanged to some methods of your manager class
    • send signals from your manager class to the slots of your ui widgets
    • do not subclass the widgets, it's almost always not necessary for these kind of things. Most times you will have some compound ui and a class for that, where you can do these things


  • [quote author="Volker" date="1297120524"]

    My problem is:
    I have a
    @...
    QTableView *tvMeresTabla;
    ...
    QStandardItemModel *tbl;
    ...
    tbl= new QStandardItemModel(0,18) ;
    ...
    ui->tvMeresTabla->setModel(tbl);
    @

    QStandardItemModel has 7 signals, QTableView has 9, but any of them doesn't emit selectionChanged() signal by default.
    QItemSelectionModel does have this signal, but that inherits directly QObject. Where is the place of signal emission in my QTableView + QStandardItemModel system? How to induce this system to start my function when new row is selected by clicking the mouse or keyboard up/down arrow or PgUp/PgDown key?

    @QObject::connect(MainWindow->tbl, SIGNAL( ???
    or
    QObject::connect(ui->tvMeresTabla, SIGNAL(???@



  • Connect to a signal of the selection model attached to the view:

    @
    connect(
    ui->tvMeresTabla->selectionModel(),
    SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
    this,
    SLOT(slotForHandlingSelectionChanged(QItemSelection,QItemSelection))
    );
    @

    Adjust the object pointer and method name for the slot part (lines 4 + 5).

    Be aware, that the signal and slot signatures in the connect statement need not be literally the same as the actual ones (in regard to const modifiers and references).



  • Thank you very much, Volker, that part was missed at me: QTableView has a QItemSelectionModel, what emits the signal.
    Generally: it seems for me, that screen widgets often lack emitting the signals I am interested in.
    Can I say that those complex/tricky screen widgets always have child/connected other objects that are emitters of the signals needed?
    If not, what is the recommended way to add a signal to a built-in Qt widget?

    Let's suppose I have a QLabel and I want to "sense" the mouse clicking the label to repaint the it. How to do this? (I would subclass QLabel...I found a "void QLabel::mousePressEvent(QMouseEvent *ev)" in qlabel.h )



  • No, normally the widgets have their own signals. It is seldom needed to grab signals from sub objects (not necessarily widgets!).

    The item view classes are a special beast.

    • If you use the view classes (QListView, QTableView, QTreeView), you need a model anyways. In fact you entirely work on models, so you have to connect to the signals of the selectionModel().
    • If you use the convenience widget classes (QListWidget, QTableWidget, QTreeWidget) you have some additional signals sent from the widget itself.

    Another case where you might to connect to sub objects signals is QTextEdit with QTextDocument; but in general the widgets provide all the signals you need.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.