LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   QT: run-time layout rendering and a bit more ;-) (https://www.linuxquestions.org/questions/programming-9/qt-run-time-layout-rendering-and-a-bit-more-%3B-874648/)

Ramurd 04-12-2011 05:25 PM

QT: run-time layout rendering and a bit more ;-)
 
Hi all, in the constructor of one of my widgets I perform the rendering at run-time; Some aspects here I have not grabbed yet, and documentation did not really clear this up to me so far. For the good order, I show my code here:

PHP Code:

StatAdminForm::StatAdminForm(QWidget *parent) :
    
QWidget(parent),
    
ui(new Ui::StatAdminForm)
{
    
ui->setupUi(this);

    
QLabel *headerLabel;
    
QSqlTableModel *table;
    
QTableView *view;

    
headerLabel = new QLabel(this);
    
headerLabel->setText("Stats Administration");

    
table = new QSqlTableModel;
    
table->database();
    
table->setTable("stats");
    
table->setSort(0,Qt::AscendingOrder);
    
table->select();

    
view = new QTableView(this);
    
view->setModel(table);
    
view->resizeColumnsToContents();

    
QGridLayout *lo = new QGridLayout;
    
lo->addWidget(headerLabel);
    
lo->addWidget(view);
    
this->setLayout(lo);


Things don't really look bad here, except that my tableview is stretched out over the whole width of the widget. How can I make sure the whole tablewview widget looks cut for the job? (no "empty" space and no absurd stretching of the columns)

The table referenced here has 3 columns: id, name and long_name;
I actually want to remove "id" from the view, or rather: let this be the index in the database, rather than the row-number in the view. How can I replace the verticalIndex with the data in column "id" (which is the primary key, and thus unique) in such a way that the table can still be edited? (having issues in this part)

dugan 04-12-2011 05:26 PM

Why did you wrap C++ code in PHP tags? Use CODE tags instead please.

To get rid of the stretching of the columns, you can use the QTableView::resizeColumnsToContents().

Ramurd 04-12-2011 05:29 PM

I like pretty colors ;-)
As you can see here, it makes code a bit more readable (at least to me):
Code:

StatAdminForm::StatAdminForm(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::StatAdminForm)
{
    ui->setupUi(this);

    QLabel *headerLabel;
    QSqlTableModel *table;
    QTableView *view;

    headerLabel = new QLabel(this);
    headerLabel->setText("Stats Administration");

    table = new QSqlTableModel;
    table->database();
    table->setTable("stats");
    table->setSort(0,Qt::AscendingOrder);
    table->select();

    view = new QTableView(this);
    view->setModel(table);
    view->resizeColumnsToContents();

    QGridLayout *lo = new QGridLayout;
    lo->addWidget(headerLabel);
    lo->addWidget(view);
    this->setLayout(lo);
}


graemef 04-12-2011 07:36 PM

If I understand your requirements correctly then you might want to look at putting your view in a horizontal layout and then use a horizontal spacer. But you might need to invest sometime in working out how large you want the view to really be. To do that you need to look at the header of the view and then the size hints, something like:
Code:

int widgetSize = view->header()->sectionSizeHint(0)
              + view->header()->sectionSizeHint(1)
              + view->header()->sectionSizeHint(2);

You possibly don't need the first hint if you hide that field.
You may want to put that code in a overloaded refresh method of the window.

Ramurd 04-13-2011 05:46 AM

I changed the code a bit; upon popular request I'll put it in code-tags, instead of php-tags (so much for pretty colors):

Code:

StatAdminForm::StatAdminForm(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::StatAdminForm)
{
    ui->setupUi(this);

    QLabel *headerLabel;
    QSqlTableModel *table;
    QTableView *view;
    QSpacerItem *spacer;

    headerLabel = new QLabel(this);
    headerLabel->setText("Stats Administration");

    table = new QSqlTableModel;
    table->database();
    table->setTable("stats");
    table->setSort(0,Qt::AscendingOrder);
    table->select();

    /* below 2 lines are my attempt to get column 0 as the vertical index;
    * doesn't work: when removing column 0, updates in the table are not sent
    * to the database due to this error:
    *    QSqlQuery::value: not positioned on a valid record
    */
    //table->headerData(0,Qt::Vertical,Qt::DisplayPropertyRole);
    //table->removeColumn(0);

    view = new QTableView(this);
    view->setModel(table);
    view->resizeRowsToContents();
    view->resizeColumnsToContents();

    /* calculating the size of hint this way does not seem to have any effect */
    //int hint = view->horizontalHeader()->sectionSizeHint(0) +
    //        view->horizontalHeader()->sectionSizeHint(1) +
    //        view->horizontalHeader()->sectionSizeHint(2);

    int hint = view->columnWidth(0) + view->columnWidth(1) + view->columnWidth(2);
    qDebug() << "hint =" << hint;
    view->setMinimumWidth(hint);
    view->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    QVBoxLayout *vlo = new QVBoxLayout;

    vlo->addWidget(headerLabel);
    vlo->addWidget(view);
    vlo->setAlignment(headerLabel,Qt::AlignCenter);
    vlo->setAlignmnet(view,Qt::AlignLeft);

    this->setLayout(vlo);
    this->repaint();
}

The outcome is getting closer: the TableView is shown in full length (what I wanted), but does not have enough width this time (whereas it expanded to the entire width of the widget earlier - which was too much), while there is plenty of space to the right of the widget, so it must have space to expand, which it doesn't for some reason. QGridLayout does not seem to allow spacers (insertItem() only accepts a LayoutItem and a spacer is not a widget. I guess I'm using the wrong style of Layout here, but my attempts so far have not yet borne fruit; A spacer does not seem logical here at this point, unless it is to prevent the widget to take too much space; but right now nothing I do seems to expand the thing anymore...

graemef 04-13-2011 07:30 AM

You probably need to move the widget resize out of the constructor into a different method which you attach to via the geometriesChanged() signal.

If so, the reasoning would be that the view is not populated during the constructor and so the sizehints don't yield meaningful values.

Here is an example of something I have done
Code:

void StatWordCount::refresh()
{
  ui->treeStatsChapter->header()->setResizeMode(1,QHeaderView::ResizeToContents);
  ui->treeStatsChapter->header()->setResizeMode(2,QHeaderView::ResizeToContents);
  int newSize = ui->treeStatsChapter->header()->size().rwidth()
              - ui->treeStatsChapter->header()->sectionSizeHint(1)
              - ui->treeStatsChapter->header()->sectionSizeHint(2)
              ;
  ui->treeStatsChapter->header()->resizeSection(0,newSize);
  ui->treeStatsChapter->viewport()->update();
}

Not exactly what you want, it resizes the first column to use up all remaining space. The constructor had the following connections:
Code:

    connect (ui->treeStatsChapter->header(), SIGNAL(geometriesChanged()),this,SLOT(refresh()));
    connect (ui->treeStatsChapter->header(), SIGNAL(sectionResized(int, int, int)),this,SLOT(refresh()));


Ramurd 04-13-2011 08:06 AM

interesting, will fiddle around with that;

In the mean time I have been trying and thinking more, and I think I got an error in my thinking:

The width of the widget is more than the size of the columns:
The widget has 2 borders on the side (duh), each taking a width of 1, hence:
int num_borders = 2;
The widget is filled with 3 columns, each has a border to the left and to the right, but sharing one if one is already there
The maths on that would make num_columns + 1 = amount of column-borders (each with a width of 1)
int num_columns = 3; // gives 4 borders |1|2|3| + num_borders for the widget

The vertical header also takes space; So I get to this calculation, and this seems to fit perfectly:
Code:

    hint = view->columnWidth(0)
        + view->columnWidth(1)
        + view->columnWidth(2)
        + view->verticalHeader()->width()
        + (num_columns + 1)
        + num_borders;

Then I can set the width like this:
Code:

    view->setMinimumWidth(hint);
    view->setMaximumWidth(hint);
    view->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

So, sizing the widget to fit perfectly, although it takes way more code than I had expected, actually does work. Now to set the verticalHeader data to the "id" column so I can hide that one from the view (since I don't want people to enter / alter data on that field, whereas I don't mind about the other columns, in fact: it's there to alter the other columns.)


All times are GMT -5. The time now is 03:19 PM.