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

QDataWidgetMapper messed column indexes



  • Hello community,

    I'm trying to use QDataWidgetMapper lately as suggested in one use case by @JonB.
    It's mostly working very well, but this case makes me puzzled about how is this happening: I have database with table and pull some data into QSqlTableModel. Now, when I list the columns I get expected columns in expected order.
    I assign that model to the QDataWidgetMapper instance:

            self.mapper.setModel(self.model)
    

    When I list the columns in the assigned model:

            for i in range(mapper.model().columnCount()):
                print(str(i) + "    " + mapper.model().headerData(i,Qt.Horizontal))
    

    ...it again gives expected columns in expected orders.
    So I assign columns to widgets like:

            ...
            mapper.addMapping(propsbws.txtWidth,          12)
            mapper.addMapping(propsbws.txtHeight,         13)
            ...
    

    But the width and height should have indexes 11 and 12. Indexes appear to be shifted or missing altogether, but certainly not corresponding to the listed numbers.

    How can I find/list true positions of columns in the model as per QDataWidgetModel view point?


  • Lifetime Qt Champion

    Hi
    How much are they shifted?
    QDataWidgetMapper counts the first col as zero where we humans would call it 1.

    What does this list ?
    for i in range(mapper.model().columnCount()):
    print(str(i) + " " + mapper.model().headerData(i,Qt.Horizontal))



  • @Oak77 said in QDataWidgetMapper messed column indexes:

    I'm trying to use QDataWidgetMapper lately as suggested in one use case by @johnb003.

    I kind of think that might be me, @JonB, as I remember recommending this to you recently, rather than @johnb003, who made a single, unrelated post back in 2014 :)

    This should all work fine, don't know what you are seeing that appears to be wrong. You had better answer @mrjj's question, or show us exactly what you are seeing/appears to be wrong.



  • @mrjj said in QDataWidgetMapper messed column indexes:

    Hi
    How much are they shifted?
    QDataWidgetMapper counts the first col as zero where we humans would call it 1.

    What does this list ?
    for i in range(mapper.model().columnCount()):
    print(str(i) + " " + mapper.model().headerData(i,Qt.Horizontal))

    Yep, I get that, but it's actually not all shifted, I get expected results to some point. It seems I was wrong about "messed", it may be only more or less shifted. In particular note the shift between 9 and 11 (missing 10).

    The assigned indexes were set empirically based on values appearing in widgets, expected index is in comment at the end of the line:

    #mapper.addMapping(propsbws.rowIdx,           0)    # Expected 0    OK
            mapper.addMapping(propsbws.txtName,           1)    # Expected 1    OK
            mapper.addMapping(propsbws.chbGid,            2)    # Expected 2    OK
            mapper.addMapping(propsbws.chbDet,            3)    # Expected 3    OK
            mapper.addMapping(propsbws.chbNew,            4)    # Expected 4    OK
            mapper.addMapping(propsbws.chbPick,           5)    # Expected 5    OK
            #mapper.addMapping(propsbws.,                 6)    # (not mapped)
            #mapper.addMapping(propsbws.,                 7)    # (not mapped)
            #mapper.addMapping(propsbws.,                 8)    # (not mapped)
            mapper.addMapping(propsbws.txtLL,             9)    # Expected 9    OK
            mapper.addMapping(propsbws.intGidCW,          11)   # Expected 10   NOK <<<<<
            mapper.addMapping(propsbws.txtWidth,          12)   # Expected 11   NOK
            mapper.addMapping(propsbws.txtHeight,         13)   # Expected 12   NOK
            mapper.addMapping(propsbws.txtUnit,           14)   # Expected 13   
            mapper.addMapping(propsbws.chbEtb,            15)   # Expected 14
            mapper.addMapping(propsbws.chbNL,             16)   # Expected 15
            mapper.addMapping(propsbws.spFS,              17)   # Expected 16
            #mapper.addMapping(propsbws.txtFV,            18)   # Expected 17       
            mapper.addMapping(propsbws.txtNF,             19)   # Expected 18
            mapper.addMapping(propsbws.spD,               20)   # Expected 19
            mapper.addMapping(propsbws.txtTT,             21)   # Expected 20   OK
            mapper.addMapping(propsbws.cbTab,             22)   # Expected 21
            mapper.addMapping(propsbws.cbVC,              23)   # Expected 22
            mapper.addMapping(propsbws.cbDC,              24)   # Expected 23
            mapper.addMapping(propsbws.cbFC,              25)   # Expected 24
            mapper.addMapping(propsbws.txtFV,             26)   # Expected 25
            #mapper.addMapping(propsbws.txtEF,            27)   # Expected 26   NOK
            mapper.addMapping(propsbws.txtGidOrder,       28)   # Expected 27   NOK
            mapper.addMapping(propsbws.txtDetOrder,       29)   # Expected 28   NOK
            mapper.addMapping(propsbws.txtLW,             30)   # Expected 29   NOK, not working - missing?
    

    This is HeaderData listing from the model:

    0    ID
    1    CName
    2    IsGid
    3    IsDet
    4    IsNew
    5    IsPick
    6    FID
    7    PID
    8    CT
    9    LL
    10    GidCW
    11    DetWidth
    12    DetHeight
    13    Units
    14    IsEtb
    15    IsNL
    16    FS
    17    FV
    18    NF
    19    DP
    20    TT
    21    FTab
    22    FVC
    23    FDC
    24    FFC
    25    FFV
    26    EF
    27    GidOrder
    28    DetOrder
    29    LW
    

    It's quite difficult to empirically finding out the indexes, especially with wife and kids around :-).



  • @JonB said in QDataWidgetMapper messed column indexes:

    @Oak77 said in QDataWidgetMapper messed column indexes:

    I'm trying to use QDataWidgetMapper lately as suggested in one use case by @johnb003.

    I kind of think that might be me, @JonB, as I remember recommending this to you recently, rather than @johnb003, who made a single, unrelated post back in 2014 :)

    This should all work fine, don't know what you are seeing that appears to be wrong. You had better answer @mrjj's question, or show us exactly what you are seeing/appears to be wrong.

    Yep, there's around 100% chance it might be you :-). I'm sorry, it's fixed.
    Providing output wasn't that easy (some columns are unused, I messed it a bit due to shifted indexes, etc.), but it's now finished and posted above. I was hoping I'm missing something obvious that would save me that labour intensive index guessing and testing.



  • @Oak77 said in QDataWidgetMapper messed column indexes:

        mapper.addMapping(propsbws.txtLL,             9)    # Expected 9    OK
        mapper.addMapping(propsbws.intGidCW,          11)   # Expected 10   NOK <<<<<
    

    This is where it starts to go wrong. On my fingers, 10 comes between 9 and 11, yet you do not have that nice number in your second argument? Anyway, this is for you to look at, QDataWidgetMapper works fine, it;s just a mapping between a particular column number and a widget. So maybe you need to chop out every line till you find out/get it right....



  • @JonB said in QDataWidgetMapper messed column indexes:

    @Oak77 said in QDataWidgetMapper messed column indexes:

        mapper.addMapping(propsbws.txtLL,             9)    # Expected 9    OK
        mapper.addMapping(propsbws.intGidCW,          11)   # Expected 10   NOK <<<<<
    

    This is where it starts to go wrong. On my fingers, 10 comes between 9 and 11, yet you do not have that nice number in your second argument? Anyway, this is for you to look at, QDataWidgetMapper works fine, it;s just a mapping between a particular column number and a widget. So maybe you need to chop out every line till you find out/get it right....

    Yep, maybe I didn't make myself clear, that that is exactly the place where I'm lost. It should be as simple as that what you see in the model column list would be what you get in the assigned widgets. The argument 10 should give column gidCW which is in the model in a column with index 10, but instead I have to skip an index and use 11 in order to obtain that column [to see correct values in assigned widget]. And if we go all the way to the end, the last argument gives 2nd last model column and if I try to map +1 column, I get no value (so I can't map the last column in the model).

    I can only empirically see what values I get in widgets and I can list the model columns as I did. I don't know if I can get any debugging in between, i.e. like in VS .NET, where you can set a breakpoint and drill through the structure of objects. Of course, I may do something stupid since I'm learning this stuff, I'd have no hesitation to admit that. I spent half a day in the docs and testing this... :-)


  • Lifetime Qt Champion

    @Oak77
    Hi
    Im also a bit confused as I dont get why the cols dont match up.
    Do you add anything to the QSqlTableModel manually or does it all comes from the connected table ?



  • OK, further testing showed that there's a value of the lost last column No. 29 located under the index 10. So at least I have all the columns. However, I still have no idea what I did to cause this nasty little mess. I wonder if there could be any sort of sort affecting the order of the columns.



  • @mrjj said in QDataWidgetMapper messed column indexes:

    @Oak77
    Hi
    Im also a bit confused as I dont get why the cols dont match up.
    Do you add anything to the QSqlTableModel manually or does it all comes from the connected table ?

    Thanks for looking at it. No, I didn't add anything to the data.

    I just noticed that I have sorting applied to this particular data table. It shouldn't cause this situation, because it sorts rows, not columns.. AFAIK there's no way to sort columns in the QHeaderData.

    I wonder, if this could be caused by providing a QSqlTableModel (inherits QSqlQueryModel, that in turn QAbstractTableModel and that QAbstractItemModel), while the documentation states a QAbstractItemModel should be supplied.



  • @Oak77
    No, that should be fine. Try removing whatever sorting you are applying and see where you are.



  • @JonB said in QDataWidgetMapper messed column indexes:

    @Oak77
    No, that should be fine. Try removing whatever sorting you are applying and see where you are.

    OK, tested, removing model.setSort(28,Qt.AscendingOrder) didn't change anything.



  • @Oak77
    If you have a QSqlTableModel, are you relying in the columns coming back in some order which they are not? Do you know what SELECT statement is being issued?



  • @JonB said in QDataWidgetMapper messed column indexes:

    @Oak77
    If you have a QSqlTableModel, are you relying in the columns coming back in some order which they are not? Do you know what SELECT statement is being issued?

    I think the answer is No, I don't rely on any order it would figure out and I supply list of columns. I have a data access class and method which receives a list of columns and assigns them to the model:

            for i, ColName in enumerate(ColumnList):
                model.setHeaderData(i, QtCore.Qt.Horizontal, ColName)
                print("index = " + str(i) + "       Col.name = " + ColName)
    

    Note, that I added the print just now and it shows the same stuff we see in the end, when listing the model from within the self.mapper, the instance of the QDataWidgetMapper.

    The main thing is though, that when listing the columns from within the self.mapper, it should be what should be used to map the columns. Or am I wrong? So it almost looks like the QDataWidgetMapper class does this to the order of the columns while processing the self.model().



  • OK, one more way to debug that I found: I used QDataWidgetMapper.mappedWidgetAt(int) to list columns that are mapped, like that:

            for i in range(mapper.model().columnCount()):
                w = mapper.mappedWidgetAt(i)
                if w != None:
                    print(str(i) + "    " + w.objectName())
    

    And the result is:

    1   CName
    2   IsGid
    3   IsDet
    4   IsNew
    5   IsPick
    9   LL
    10   LW               # <<<<<<<< Note the last column is here
    11   GidCW
    12   DetWidth
    13   DetHeight
    14   Units
    15   IsEtb
    16   IsNL
    17   FS
    18   FV
    19   NF
    20   DP
    21   TT
    22   FTab
    23   FVC
    24   FDC
    25   FFC
    26   FFV
    27   EF
    28   GidOrder
    29   DetOrder
    

    So the mapper has a different order from what is in the self.model().


  • Lifetime Qt Champion

    Hi
    Im a bit lost here too as i see no reason
    that mapper.model() should have different col order than QSqlTableModel ( self.model() ?)
    since we supply the mapper with the model as pointer so it should be same model.



  • @Oak77
    It is as @mrjj & I have said. It should all work. QDataWidgetMapper just works off the model's columns. If you want to resolve this you really need to stop with the fragments of code you have shown so far and rebuild from a small, standalone example, which will work, till you encounter whatever it is you have changed. We will not be able to say anything from the various fragments you have given here.


  • Lifetime Qt Champion

    Hi
    I tried to recreate it so I used your result list here to make the table

    alt text

    I then mapped it to a bunch a lineEdits, skipping 5,6,7 ( well 4,5,6)

       int range = 0;
        for (auto name : names) {
            QLineEdit *line = new QLineEdit(this);
            ui->vertL->addWidget(line);
            line->setPlaceholderText(name);
            if (range != 5 && range != 6 && range != 7 )
                map->addMapping(line, cc++ );
            else
                cc++;
    
            range++;
        }
        map->toFirst();
    

    alt text

    but the values always come as expected

    alt text

    Then i tried to dump the cols like you did

    
        for (int cc  = 0; cc < map->model()->columnCount(); cc++ ) {
          qDebug().noquote().nospace() << cc << " = " <<  map->model()->headerData(cc, Qt::Horizontal) ;
        }
    

    But they still come in the expected order.

    0 = QVariant(QString, ID)
    1 = QVariant(QString, CName)
    2 = QVariant(QString, IsGid)
    3 = QVariant(QString, IsDet)
    4 = QVariant(QString, IsNew)
    5 = QVariant(QString, IsPick)
    6 = QVariant(QString, FID)
    7 = QVariant(QString, PID)
    8 = QVariant(QString, CT)
    9 = QVariant(QString, LL)
    10 = QVariant(QString, GidCW)
    11 = QVariant(QString, DetWidth)
    12 = QVariant(QString, DetHeight)
    13 = QVariant(QString, Units)
    14 = QVariant(QString, IsEtb)
    15 = QVariant(QString, IsNL)
    16 = QVariant(QString, FS)
    17 = QVariant(QString, FV)
    18 = QVariant(QString, NF)
    19 = QVariant(QString, DP)
    20 = QVariant(QString, TT)
    21 = QVariant(QString, FTab)
    22 = QVariant(QString, FVC)
    23 = QVariant(QString, FDC)
    24 = QVariant(QString, FFC)
    25 = QVariant(QString, FFV)
    26 = QVariant(QString, EF)
    27 = QVariant(QString, GidOrder)
    28 = QVariant(QString, DetOrder)
    29 = QVariant(QString, LW)

    So I really cant find a way to see what you see. Sadly.



  • @mrjj said in QDataWidgetMapper messed column indexes:

    Hi
    I tried to recreate it so I used your result list here to make the table
    ....
    So I really cant find a way to see what you see. Sadly.

    Thank you very much! I'll study your example and I'll try to find a difference. In the meanwhile I set to make a simplified example width a Chinook database table, but I didn't finished it yet. It will take me probably few days to study everything.


  • Lifetime Qt Champion

    @Oak77
    Hi
    You are welcome to have my test project to play around with but
    it's c++ so didn't include it as you seem to use python so I guess you don't have a c++ compiler
    just like i don't have python installed.



  • @mrjj said in QDataWidgetMapper messed column indexes:

    @Oak77
    it's c++ so didn't include it as you seem to use python so I guess you don't have a c++ compiler
    just like i don't have python installed.

    That's perfectly fine, I have zero C++ skills but I can read it a bit. This proved that I have to look for a source of the problem within my code.

    I found I was wrong in one particular point: Setting HeaderData does not define the columns of the query. I found that coincidentally with a different example, where it clearly shown way more columns than what was set. This also means that the query itself might be already having a different order of columns. I'll have a look at it once behind the incident PC to confirm it.

    However, it raises another question and that is how a user is supposed to define the columns without using setQuery, because the documentation clearly states using it should be avoided. I'll open another thread for this particular interesting question.

    EDIT: Well, thinking about that, itwon't change the fact, that model shows different order from mapping, because the query is defined before the model is created and consequently used in the mapper.



  • @Oak77 said in QDataWidgetMapper messed column indexes:

    Setting HeaderData does not define the columns of the query

    Indeed, header data is just header data. It has no effect on any query. I did wonder if you were doing something like this, but we couldn't tell from the code you gave.... I'll go and look at your new question...


Log in to reply