widgetattribute example c++ qt

c++ - example - ¿Cómo determinar el tamaño correcto de un QTableWidget?



qwidget table example (7)

¿Hay alguna manera de establecer el tamaño "correcto" de un QTableWidget? (Soy un novato) Este código de prueba tiene solo 25 líneas de longitud, en dos archivos, con el archivo Test.h:

#include <QtGui> class Test : public QMainWindow { Q_OBJECT public: Test(); };

y el archivo Test.cpp:

#include "Test.h" Test::Test() : QMainWindow() { QVBoxLayout *vbox = new QVBoxLayout; QPushButton *btn = new QPushButton("Hello World etc etc etc etc etc"); QTableWidget *tbl = new QTableWidget(2, 2); vbox->addWidget(btn); vbox->addWidget(tbl); QWidget *w = new QWidget; setCentralWidget(w); w->setLayout(vbox); resize(1, 1); } int main(int argc, char *argv[]) { QApplication app(argc, argv); Test test; test.show(); app.exec(); }

Entonces el comando:

qmake -project && qmake && make && ./Test

da la ventana:

Pero lo que queremos, por supuesto, es algo así como:

Usar tbl->width() parece ser inútil, ya que da un valor por defecto de 640 antes de test.show() , y el valor no deseado de 195 después. He visto las sugerencias y políticas de tamaño de Qt hasta que mi cabeza giró, y probé setResizeMode(QHeaderView::Fixed) y setStretchLastSection(false) . Tal vez me estoy perdiendo algo obvio? Esto es con Qt 4.7.4 en CentOS 5, si esto es importante. Gracias por cualquier ayuda.

Editar : en respuesta a DK, si la línea resize(1, 1); de resize(1, 1); no está presente, existe el problema igual y opuesto : la ventana es demasiado grande.

Y en respuesta a Donotalo, agregando:

tbl->setMaximumWidth(222); tbl->setMinimumWidth(222); tbl->setMaximumHeight(88); tbl->setMinimumHeight(88);

dará el tamaño de ventana deseado (al menos en mi máquina), pero no de la manera deseada. ¿Cómo debemos calcular las ''constantes'' 222 y 88?

Y la respuesta de Ton a Qt: ¿Cómo forzar un widget oculto para calcular su diseño? no parece funcionar aquí: la adición de tbl->setAttribute(Qt::WA_DontShowOnScreen); tbl->show(); tbl->setAttribute(Qt::WA_DontShowOnScreen); tbl->show(); dejó el valor de tbl->width() sin cambios en 640.


Aquí está mi solución (pitonica) a este problema:

table.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) table.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) table.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff) table.resizeColumnsToContents() table.setFixedSize(table.horizontalHeader()->length()+table.verticalHeader()->width(), table.verticalHeader()->length()+table.horizontalHeader()->height())

Esto me da una tabla con un tamaño que envuelve perfectamente todas las filas y columnas.


El hilo ¿Cómo establecer un tamaño preciso de QTableWidget para evitar que tenga barras de desplazamiento? (Qt-interest Archive, junio de 2007) entre Lingfa Yang y Susan Macchia parece resolver mi pregunta. Voy a publicar más detalles en breve, si mi prueba funciona.

Actualización n. ° 1 : mi prueba ahora genera una ventana de aspecto agradable:

El código de prueba completo para esto, con Test.h sin cambios, es:

#include "Test.h" static QSize myGetQTableWidgetSize(QTableWidget *t) { int w = t->verticalHeader()->width() + 4; // +4 seems to be needed for (int i = 0; i < t->columnCount(); i++) w += t->columnWidth(i); // seems to include gridline (on my machine) int h = t->horizontalHeader()->height() + 4; for (int i = 0; i < t->rowCount(); i++) h += t->rowHeight(i); return QSize(w, h); } static void myRedoGeometry(QWidget *w) { const bool vis = w->isVisible(); const QPoint pos = w->pos(); w->hide(); w->show(); w->setVisible(vis); if (vis && !pos.isNull()) w->move(pos); } Test::Test() : QMainWindow() { QVBoxLayout *vbox = new QVBoxLayout; QPushButton *btn = new QPushButton("Hello World etc etc etc etc etc"); QTableWidget *tbl = new QTableWidget(2, 2); vbox->addWidget(btn); vbox->addWidget(tbl); setCentralWidget(new QWidget); centralWidget()->setLayout(vbox); layout()->setSizeConstraint(QLayout::SetMinimumSize); // or SetFixedSize tbl->setVerticalHeaderItem(1, new QTableWidgetItem("two")); // change size myRedoGeometry(this); tbl->setMaximumSize(myGetQTableWidgetSize(tbl)); tbl->setMinimumSize(tbl->maximumSize()); // optional } int main(int argc, char *argv[]) { QApplication app(argc, argv); Test test; test.show(); app.exec(); }

Algunas notas:

  • La inclusión de verticalScrollBar()->width() hilo anterior parece ser incorrecta. Y, en mis pruebas, esto siempre fue un valor predeterminado de 100, o el valor 15, si se había mostrado la barra de desplazamiento.

  • Aplicando el show(); hide(); show(); hide(); la secuencia solo para QTableWidget no fue suficiente para obligar a Qt a volver a calcular la geometría en esta prueba. Necesitaba aplicarlo a toda la ventana.

  • Cualquier sugerencia para mejoras sería bienvenida. (Esperaré un poco antes de aceptar mi propia respuesta, en caso de que haya mejores soluciones).

Actualización # 2 :

  • El hilo Qt-interest puede estar equivocado (o, al menos, no está de acuerdo con mi versión de Qt que ejecuta mi máquina) con respecto a los detalles sobre cómo calcular el tamaño: el +1 para cada línea de cuadrícula es innecesario, pero se necesita un +4 general .

  • Todavía estoy trabajando en layout()->invalidate() vs. ej. QT: cómo obtener una vista previa de los tamaños de widgets en el diseño ANTES de un show () .

Actualización # 3 :

  • Esta es mi versión final, pero no estoy muy contento con ella. Cualquier mejora sería muy bienvenida.

  • Cosas como adjustSize() y layout()->invalidate() y Qt::WA_DontShowOnScreen no parecen ayudar.

  • El blog Shrinking Qt widgets al tamaño mínimo necesario es interesante, pero el uso de setSizeConstraint() es igual de bueno.

  • Los setSizeConstraint() y move() son necesarios para los cambios posteriores a la tabla, que no se muestran aquí.

  • Hubo algo extraño en mi prueba, hecho en CentOS 5 con Qt 4.6.3 y 4.7.4. Para el hide(); show(); hide(); show(); secuencia, la posición de la ventana se guarda / restaura. Pero aproximadamente el 25% de las veces (el patrón era irregular), la posición restaurada sería de 24 píxeles más en la pantalla, presumiblemente la altura del título de la ventana. Y aproximadamente el 10% del tiempo el valor devuelto por pos() sería nulo . El sitio de Qt dice que para X11 necesita una nifty heuristics and clever code para esto, pero algo parece estar roto en alguna parte.


Estaba lidiando con el mismo problema y modifiqué las respuestas anteriores para obtener un código de trabajo correcto.

Primero, obtenemos los márgenes de contenido de QTableWidget . Si solo quiere ajustar su ancho, solo necesita deshabilitar la barra de desplazamiento horizontal .:

int w = 0, h = 0; ui->tableWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->tableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); w += ui->tableWidget->contentsMargins().left() + ui->tableWidget->contentsMargins().right(); h += ui->tableWidget->contentsMargins().top() + ui->tableWidget->contentsMargins().bottom();

Luego, agregamos el ancho del encabezado vertical a w . El encabezado vertical es una columna especial que contiene índices de filas y está habilitado de manera predeterminada. también agregamos la altura del encabezado horizontal a h . El encabezado horizontal es una fila especial que contiene títulos de columna.

w += ui->tableWidget->verticalHeader()->width(); h += ui->tableWidget->horizontalHeader()->height();

Luego, agregamos el ancho de cada columna a w , y la altura de cada fila a h .

for (int i=0; i<ui->tableWidget->columnCount(); ++i) w += ui->tableWidget->columnWidth(i); for (int i=0; i<ui->tableWidget->rowCount(); ++i) h += ui->tableWidget->rowHeight(i);

Ahora, si w o h son demasiado grandes para caber en la ventana, los reducimos para que quepan en ui->centralWidget->contentsRect() .

if (w > ui->centralWidget->contentsRect().width()) w = ui->centralWidget->contentsRect().width(); if (h > ui->centralWidget->contentsRect().height()) h = ui->centralWidget->contentsRect().height();

Lamentablemente, no conozco una forma mejor de aplicar w y h para establecer el ancho y la altura de QTableWidget . Si uso:

ui->tableWidget->setMinimumWidth(w); ui->tableWidget->setMaximumWidth(w); ui->tableWidget->setMinimumHeight(h); ui->tableWidget->setMaximumHeight(h);

Entonces el usuario no podrá cambiar el tamaño del widget en absoluto. Creo que necesitamos usar algún tipo de diseño manual.

Puede parecer un poco fuera de tema, pero si desea que su tabla tenga una vista más atractiva, use este comando para cambiar el tamaño de las columnas y adaptarlas a sus datos:

ui->tableWidget->resizeColumnsToContents();


No puedo comentar la publicación de Joseph Qunesey / Celdor, así que la escribo aquí: para recuperar el valor verdadero de QStyle::PM_TitleBarHeight , debes hacerlo de la siguiente manera:

QStyle *style; if(tv->style()) { style = tv->style(); } else { style = QApplication::style(); } int titleBarHeight = style->pixelMetric(QStyle::PM_TitleBarHeight));

Eso es porque la enumeración no tiene asignados valores exactos. Creo que su incomprensión de cómo funciona fue debido a la documentation engañosa de Qt documentation donde parece que la enumeración representa directamente los valores, mientras que, por supuesto, no (ya que depende del estilo).


Para obtener el ancho de la tabla, sume el ancho de los encabezados verticales y horizontales y el doble del ancho del cuadro. Lo mismo aplica para la altura:

w = verticalHeader()->width() + horizontalHeader()->length() + frameWidth()*2 h = horizontalHeader()->height() + verticalHeader()->length() + frameWidth()*2

Hay varias maneras de configurarlos según sus circunstancias. El preferido probablemente sea anular sizeHint () para devolver sus valores. De esta manera, la tabla se puede cambiar de tamaño, pero a falta de otros requisitos será su tamaño.

La clave para hacer que esto funcione es usar el método length() en los lugares correctos en lugar de simplemente width() o height() . No estoy exactamente seguro de por qué, pero aquí hace lo correcto ;-)


Recientemente, encontré el mismo problema. Probé decenas de funciones encontradas por Google en Qt Center, Qt Project, pero ninguna de ellas me dio el tamaño adecuado. Hice esa función, que creo que calcula el tamaño de mesa más cercano. La función proporciona un tamaño vertical adecuado pero un poco mayor horizontal; parece que todavía cubre una barra de desplazamiento vertical. Además, verifiqué si las dimensiones de la mesa superan el tamaño de un escritorio:

const QRect MyApp::adjustTableSize( QTableView* tv, const QVBoxLayout* lay, const int& maxRows, const int& maxCols) { // get Desktop size using std::size_t; QDesktopWidget desktop; size_t desW = desktop.screen()->width(); size_t desH = desktop.screen()->height(); int leftM,rightM,topM,bottomM; lay->getContentsMargins(&leftM,&topM,&rightM,&bottomM); size_t extraTopHeight = topM + tv->frameWidth(); size_t extraBottomHeight = bottomM + tv->frameWidth(); size_t extraLeftWidth = leftM + tv->frameWidth(); size_t extraRightWidth = rightM + tv->frameWidth(); size_t w = tv->verticalHeader()->width() + extraLeftWidth + extraRightWidth; size_t h = tv->horizontalHeader()->height() + extraTopHeight + extraBottomHeight; for(size_t col = 0; col < maxCols; ++col) { w += tv->columnWidth(col); } for(size_t row = 0; row < maxRows; ++row ) { h += tv->rowHeight(row); } std::size_t x,y; if((w - extraLeftWidth - extraRightWidth) > desW) { x = 0; w = desW - extraLeftWidth - extraRightWidth; } else x = (desW - w)/2; if(h - extraTopHeight - extraBottomHeight - QStyle::PM_TitleBarHeight > desH) { y = extraTopHeight + QStyle::PM_TitleBarHeight; h = desH - (extraTopHeight + QStyle::PM_TitleBarHeight + extraBottomHeight); } else y = (desH - h)/2; return QRect(x,y,w,h); }

Algunas notas secundarias:

QTableView .
Usé QTableView, pero creo que también puede funcionar con QTableWidget.

QVBoxLayout .
Estoy bastante seguro de que cualquiera de los diseños disponibles en Qt se puede usar en esta función.

Espero, esta función puede ayudar a cualquiera.


aparentemente hay - ¿algún error quizás? - en la función horizontalHeader () -> width (); esta solución funcionó para mí:

//given a QtableWidget* called x int previous_width= x->horizontalHeader()->width();//get the width //the width is relating to all the columns including the vertical headers int previous_length=x->horizontalHeader()->length();//and the length // the length is relating to all the columns excluding the size of the vertical headers int vertical_headers_width=(previous_width-previous_length); x->resizeColumnsToContents();//now we resize x->resizeRowsToContents(); //if we call again x->horizontalHeader()->width(); // we get a number that looks to me not correct (maybe is my ignorance here) x->setFixedWidth(x->horizontalHeader()->length()+vertical_headers_width); //by adding to the length of the data columns the old width_of_verticla_headers_column we get the correct size;