Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to change cursor shape at column boundaries of QTableView Qt 5.13.0



  • I have created a QTableview dynamically in a QMainWindow. I have set the model to a QSqlQueryModel and the view fills with the data properly.

    My difficulty is getting the mouse cursor to indicate the proper cursor shape when moving the mouse over the column header boundaries. The columns are set as sizeable and mouse tracking is on for this widget.

    I have tried event filters but nothing happens.

    1. how do I detect the column boundaries in order to change the cursor.
    2. If this is a mouse move event, how do I specify that event for movement over the horizontal header column boundary.
    3. if not on a column boundary the cursor needs to return to the Qt::ArrowCursor

    It would seem a logical thought that this would be a default action for a QTableWidget or a QTableView. Yet it is not and I am stuck implementing it myself.

    Any suggestions are welcome.


  • Lifetime Qt Champion

    Hi,

    What OS are you on ?
    When saying resizable, do you mean manually resizable ?



  • The OS is Linux Mint 19.2 Qt is v5.13.

    I thought I was being obvious when I said "getting the mouse cursor to indicate the proper cursor shape when moving the mouse over the column header boundaries". Looking at it now I can see where that is not as obvious as I had hoped. It is true that what is going on in my head is not completely described here.

    Yes manual sizing by click an drag. My intention is to allow the user to manually size each column. A click and drag does do that, but the cursor never changes from the arrow cursor and it is difficult to know exactly where the size handle is on the column boundary since it does not change as the cursor is moved over the columns in the header.

    The use of the built in functions for the QTableView header does resize the columns (with stored values) from the code.

    Visually speaking, the columns do show the normal grid and each column header has the right data. And the header has the column marks for the column boundaries.

    It is not obvious from the docs how to determine if the cursor is over a grid marker (column boundary) or not. I have tried various methods found on other sites but none worked at all.

    I am thinking that the solution may be with a state machine and two states but without knowing how to determine if the cursor is over a header and over a column boundary I am stuck.

    Any help would be appreciated.


  • Lifetime Qt Champion

    The cursor is set properly when it is inbetwen two sections. See also https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qheaderview.cpp.html#2722
    So I assume maybe your cursor theme has a problem. Maybe write a small test where you simply set a cursor on a widget to see if it changes as expected.



  • I have no problem changing the cursor with QApplication::setOverrideCursor(QCursor). The problem seems to be detecting the sizing handle for each column.


  • Lifetime Qt Champion

    Do you have the same issue if you use your distribution provided Qt ?


  • Lifetime Qt Champion

    If you self-compile your app, I would suggest to add some debug output inside QHeaderViewPrivate::sectionHandleAt() and the code I mentioned above.



  • SGaist I am not understanding the question. Qt v5.13.0 binary installer was downloaded as the online installer from qt.io and installed on my Linux Mint 19.2 system. Not compiled. Is that what you are having reference to?

    Other applications, like LibreOffice Calc do act correctly when moving across column boundaries. I realize that is written in a different language but it does indicate there is no system issue that prevents C++ from acting the same.



  • Just checked QtCreator again and find that at least in the properties editor of QtCreator, the cursor change occurs as expected. So I have to assume my installation of Qt is working as it should.

    There is something preventing the dynamically created QTableView in my QMainWindow from having the same action in my application.

    Is this a feature that can be enabled or disabled programmatically? If so what property is used to do this?
    Is there a property setting that overrides the display of cursor change on column boundaries?

    None of these questions have been answered in the docs nor discussed here.



  • UPDATE
    As a test I created a ridiculously simple test program that consists of a QMainWindow and a QTableWidget with 10 rows and 6 columns. Upon running this meaningless application, the cursor action works as expected channging on the column boundary when the column is crossed.

    This indicates to me that something programmatically is preventing the display of the cursor change. I have no clue what that may be.

    Is there that much difference between the QTableView and QTableWidget? Or does this mean there is so sort of bug in QTableView?


  • Lifetime Qt Champion

    @ad5xj said in How to change cursor shape at column boundaries of QTableView Qt 5.13.0:

    Is there that much difference between the QTableView and QTableWidget?

    No, there is no difference wrt to the header. QTableWidget is a QTaleView + convenience model.


  • Lifetime Qt Champion

    @ad5xj said in How to change cursor shape at column boundaries of QTableView Qt 5.13.0:

    SGaist I am not understanding the question. Qt v5.13.0 binary installer was downloaded as the online installer from qt.io and installed on my Linux Mint 19.2 system. Not compiled. Is that what you are having reference to?

    All Linux distributions that provide Qt packages also provide the corresponding development packages so that people can develop their libraries/applications using the Qt version that they have currently installed on their machine. Some distribution may apply patches to Qt or you could be using a custom style that behaves differently than what is provided by the pre-built package hence it's always a good idea to test an issue against the system provided Qt to determine if it's something that affects also your distribution or only the pre-built package.



  • SGaist such is not the case.

    This is the package supplied by the online installer for Qt binaries on Debian systems such as Linux Mint. No source for Qt libraries were used. Only the supplied pre-built binaries from the online installer. It is a very plain vanilla installation and in general works well other than is anomoly.

    The QTableView is used as is with no modification to style or use of style sheets. The QTableView object is use with all defaults and only :
    setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    was changed.

    I do agree it is a variant I have not seen before and did not expect.



  • To check whether I had introduced the problem in my code I brought up an older application that had been working. After compiling and running it, I find it too has the problem.

    So I am attempting to remove Qt and reinstall to see if it is a problem with my Qt install.


  • Lifetime Qt Champion

    @ad5xj said in How to change cursor shape at column boundaries of QTableView Qt 5.13.0:

    SGaist such is not the case.

    This is the package supplied by the online installer for Qt binaries on Debian systems such as Linux Mint. No source for Qt libraries were used. Only the supplied pre-built binaries from the online installer. It is a very plain vanilla installation and in general works well other than is anomoly.

    The QTableView is used as is with no modification to style or use of style sheets. The QTableView object is use with all defaults and only :
    setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    was changed.

    I do agree it is a variant I have not seen before and did not expect.

    There's a misunderstanding here. I do understand that you are using the pre-built package with Qt 5.13, no problem with that.

    What I am asking you do to is to re-build your application with Mint's provided Qt version and see if it behaves the same or not. If the behaviour is the same, then you likely have something fishy going on with your code or you may have found a bug. If the behaviour is different, then it might be something new that happened between the version provided by Mint and Qt 5.13.

    You can also test earlier versions of Qt to see when the behaviour changed.



  • OK, I think I have found at least a workaround.

    I created a trivial project with only a QMainWindow and a QTableWidget. This meaningless project compiled and worked as expected. So I began to add in lines to my trivial project from my other project as they occured to find the offending lines if code.

    My mainwindow constructor first line uses a QApplication::setOverrideCursor() to change the application cursor to a wait cursor, and conversely the last line contains a similar line that changes it back to an arrow cursor.

    Therein lies the problem. When those two lines were eliminated, the application works as expected. The cursor movement over column size handles does produce the expected cursor change.

    Now the question becomes whether this is a design phenomenon or a bug. That will have to be a question for Qt designers.

    For now, problem averted. I can move on with my project.

    Thanks to all who contributed.


  • Lifetime Qt Champion

    @ad5xj said in How to change cursor shape at column boundaries of QTableView Qt 5.13.0:

    Now the question becomes whether this is a design phenomenon or a bug.

    Can you please provide the source code from your testcase so we can take a look on it?



  • OK, I have never done this before but here goes. This trivial application does nothing but did provide the clues to the solution.

    In the constructor of the QMainWindow I had used QApplication::setOverrideCursor(QCursor) to change to a wait cursor at the start and again at the end to change back to an arrow cursor. It was not until those two line were eliminated that the project began to function as expected.

    Update: My user privileges are not high enough to upload files so I will include the code here:
    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include <QMainWindow>
    
    #include "ui_mainwindow.h"
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
        
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
        
    protected:
        void changeEvent(QEvent *e);
        
    private:
        class MWPriv;
        MWPriv *mwd;
    
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    

    mainwidow.cpp

    #include <QSplitter>
    #include <QSqlQueryModel>
    #include <QSqlRelationalTableModel>
    #include <QSqlQuery>
    
    #include "mainwindow.h"
    
    // -----------------------------------------------
    // LOCAL PRIVATE VAR DEFINITIONS
    //    pointed to by the *d-ptr definition in
    //    the header file
    // -----------------------------------------------
    class MainWindow::MWPriv
    {
    public:
        bool    useUTC;
        bool    dbg2file;
        bool    showstats;
        bool    tblNeedsReload;
        bool    showSrchFiltered;
    
        bool    font_bold;
        bool    font_italic;
        bool    font_underline;
    
        bool    daily_mode;
        bool    field_day;
        bool    contest_mode;
    
        bool    useQRZ;
        bool    useCallook;
    
        bool    useAltRowColor;
        bool    contEditVisible;
        bool    fdEditVisible;
        bool    formloaded;
    
        int hdrfontsize;
        int timefontsize;
        int dtlfontsize;
        int no_of_qsos;
    
        int color_R;
        int color_G;
        int color_B;
        int color_A;
    
        int uix;
        int uiy;
        int uiw;
        int uih;
    
        int rowcnt;
        int currentLog; // This is to be able to manage multiple logs without showing them all at the same time.
        int modifyingQSO;      // When modifying, the QSO is saved here.
        int selectedYear;
    
        QByteArray geo;
        QByteArray uiState;
    
        // Vals from settings for Logbook
        QString    dtlfontfamily;
        QString    hdrfontfamily;
        QString    timefontfamily;
    
        QString    hdrs;
        QString    colwidths;
    
        QString    mode_text;
        QString    dbgfile;
    
        QString    sofwareVersion;
        QString    adif_file;
        QString    xml_file;
        QString    xmlrpchost;
        QString    xmlrpcport;
    
        QString    DBConnName;
        QString    DBPath;
        QString    DBName;
        QString    DBHostName;
        QString    DBDriver;
        QString    DBUser;
        QString    DBPassWd;
        // operating station variables from settings
        QString    callsign;
        QString    firstname;
        QString    city;
        QString    ststate;
        QString    grid;
        QString    country;
        QString    cont;
        //
    
        QString    title;
        QString    fltr;
    
        QFont      hdrfont;
        QFont      dtlfont;
    
        QSqlQuery      qry;
    
        QAction        *actionShowContactEditor;
        QAction        *actionShowFDEdit;
        QAction        *actionShowNone;
        QAction        *actionShowFDStats;
    
        QActionGroup   *chkGroup;
        QActionGroup   *radGroup;
    
        QSplitter      *mainSplitter;
    
        QSqlQueryModel *model;
        QSqlRelationalTableModel *tmodel;
    };
    
    MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
    {
        //====> This breaks it QApplication::setOverrideCursor(Qt::WaitCursor);
        mwd = new MWPriv;
        mwd->tblNeedsReload = true;
        mwd->formloaded = false;
        mwd->useQRZ = false;
        mwd->useCallook = false;
        mwd->useUTC = false;
    
        ui = new Ui::MainWindow;
        ui->setupUi(this);
    
        ui->retranslateUi(this);
        //====> This breaks it QApplication::setOverrideCursor(Qt::ArrowCursor);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::changeEvent(QEvent *e)
    {
        QMainWindow::changeEvent(e);
        switch (e->type()) {
        case QEvent::LanguageChange:
            ui->retranslateUi(this);
            break;
        default:
            break;
        }
    }
    

    mainwindow.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>400</width>
        <height>300</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralWidget">
       <widget class="QTableWidget" name="tableWidget">
        <property name="geometry">
         <rect>
          <x>10</x>
          <y>10</y>
          <width>256</width>
          <height>192</height>
         </rect>
        </property>
        <property name="rowCount">
         <number>10</number>
        </property>
        <property name="columnCount">
         <number>6</number>
        </property>
        <row/>
        <row/>
        <row/>
        <row/>
        <row/>
        <row/>
        <row/>
        <row/>
        <row/>
        <row/>
        <column/>
        <column/>
        <column/>
        <column/>
        <column/>
        <column/>
       </widget>
      </widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>400</width>
         <height>24</height>
        </rect>
       </property>
      </widget>
      <widget class="QToolBar" name="mainToolBar">
       <attribute name="toolBarArea">
        <enum>TopToolBarArea</enum>
       </attribute>
       <attribute name="toolBarBreak">
        <bool>false</bool>
       </attribute>
      </widget>
      <widget class="QStatusBar" name="statusBar"/>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>
    

    Hope this helps.


  • Lifetime Qt Champion

    @ad5xj said in How to change cursor shape at column boundaries of QTableView Qt 5.13.0:

    QApplication::setOverrideCursor(QCursor)

    I don't see where you're calling it - can you please modify it so we can see the error? Thx.



  • Updated for you Christian


  • Lifetime Qt Champion

    Ok, now I see what you're doing wrong - you're setting a global override cursor so no widget will be able to change the cursor. You're looking for QGuiApplication::restoreOverrideCursor() as described in the documentation



  • OK, that worked.

    It is not obvious or even clear from the docs there is that much difference or even when it is appropriate to use one or the other.


  • Lifetime Qt Champion

    I would say this is clear enough:

    "Application override cursors are intended for showing the user that the application is in a special state, for example during an operation that might take some time.

    This cursor will be displayed in all the application's widgets until restoreOverrideCursor() or another setOverrideCursor() is called."

    /Edit: please makr the thread as solved, thx :)


Log in to reply