Resize column to text QT Table Widget Python PyQt5 [duplicate] - python

I am new to Qt and I have just managed to make a QTableView work with my model. It has fixed 3 columns. When I open a window, it look ok but when i resize the window, the QTableView itself gets resized but columns' width remains the same. Is there any build-in way to make it work? I want columns to resize to fit the edges of QTableView every the the window gets resized.

This code equally stretches each column so that they fit the table's width.
table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
Docs:
QHeaderView::setSectionResizeMode
See resize modes here.

There is a header flag to ensure that the QTableView's last column fills up its parent if resized. You can set it like so:
table_view->horizontalHeader()->setStretchLastSection(true);
However, that does not resize the other columns proportionately. If you want to do that as well, you could handle it inside the resizeEvent of your parent thusly:
void QParent::resizeEvent(QResizeEvent *event) {
table_view->setColumnWidth(0, this->width()/3);
table_view->setColumnWidth(1, this->width()/3);
table_view->setColumnWidth(2, this->width()/3);
QMainWindow::resizeEvent(event);
}
QParent class is subclass of QMainWindow.

Widgets QTableView, QTreeView and their derived classes (such as QTableWidget) have this two usefull methods:
QHeaderView* horizontalHeader() const;
QHeaderView* verticalHeader() const;
If you open documentation for a class QHeaderView, you will find methods that set up appearance and behavior of row or column header for item views. You can resolve your problem by one of these methods:
void QHeaderView::stretchLastSection( bool stretch )
As Davy Jones mentioned.
Example:
QTableView *table = new QTableView();
table->horizontalHeader()->setStretchLastSection(true);
void QHeaderView::setResizeMode( ResizeMode mode )
As mode you can set QHeaderView::Stretch or QHeaderView::ResizeToContents.
Unfortunately this method have a drawback - after it's apply you will not be able to change size of columns (or rows) manually (in GUI) or programmatically.
Example:
QTableView *table = new QTableView();
table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);

In PyQt5 you can achieve this in your table_widget by doing:
header = table_widget.horizontalHeader()
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

Related

Auto resize QLabel to fit updated QTableWidget span

I have a QTableWidget, and I have a QLabel that I put inside a cell of the table using .setCellWidget().
During run-time I change the span of the QTableWidget cell where the QLabel is, using .setSpan()
BUT when I change the span of the cell where the QLabel is, the QLabel does not resize.
Some code and screenshot below:
def generate_table(self):
global gtable
table = QTableWidget(20, 60)
gtable = table
def create_task(self):
task_widget = QWidget()
task_layout = QHBoxLayout()
task_widget.setLayout(task_layout)
task = QLabelClickable(the_task_name)
task_layout.addWidget(task)
gtable.setCellWidget(selected_row_column[0], selected_row_column[1], task_widget)
// if I include this part of the code, everything looks fine, both cell, widget and label scale properly, as visible through background color, below line is not the problem, notice its in the same function as where I set the cell widget
the_duration = 3
gtable.setSpan(selected_row, selected_column, 1, the_duration)
// Below is how I change the cell span. The rrow and ccolumn are integers, basically just cell coordinates
def save_task(self):
gtable.setSpan(rrow, ccolumn, 1, w_dr.value())
(there's a ton of code all over the place so I included what I thought is relevant, let me know what other parts of the code I should include)
This is what it should look like: (this is what the first span-changing line does)
This is what it looks like: (this is what the last line does)
My question is, How do I resize the QLabel / QWidget to auto fit the cell's updated size?
You can see the first span as correct because it's applied in the same event loop that would update the geometries of the view.
Spanning does not automatically do that (which could be a bug), so the solution is to use updateGeometries(), which:
Updates the geometry of the child widgets of the view.
Which means that all widgets of the view will be correctly resized and updated, including scroll bars and cell widgets.
def save_task(self):
gtable.setSpan(rrow, ccolumn, 1, w_dr.value())
gtable.updateGeometries()
A very important suggestion: avoid using globals, they are not handy as one would think, and in fact the often cause problems and bugs that are difficult to track; use instance members instead (eg. self.gtable).

pyqt: how to use scroll area that contains an outsized label [duplicate]

I want to overlay two widgets in QtDesigner:
There is the big QTextBrowser, and below in the down right corner should be a non-interactiv label that I am going to use as a drag-grip to resize the window (the main widget is frameless so I need to implement it).
Usually this label will sit below the QTextBrowser, which leaves on the left of the grip-label a lot of unused space. So I want to put the grip-label above the QTextBrowser. I want to achieve this in QtDesigner. But the code would look like:
QHBoxLayout *layout = new QHBoxLayout(videoWidget);
QLabel *overlayWidget = new QLabel();
overlay->setAlignment(Qt::AlignCenter);
overlay->setText("Overlaid Text");
layout->addWidget(overlay);
Or as I already did in python:
self.textedit = QTextBrowser(self);
...
gripImage=QLabel(self.textedit);
There the part between the brackets is the parent widget.
That's how it looks right now, but this is not what I want:
This is usually simplest to achieve by using QGridLayout. It allows widgets to occupy the same grid cells. For this particular problem, a 1x1 grid is enough.
Steps to try it out with designer:
Create new form, plain Widget for simplicity
Add a text edit to it (drag and drop from Widget Box), and from Object Inspector you should see it becomes child of the root widget
Add a label to it (drag and drop from Widget Box), and from Object Inspector you should see it becomes child of the root widget
Right click on the root widget (easiest in the Object Inspector), and from the bottom of context menu, select Lay out > - Lay out in Grid
Right click on the label, and from Layout alignment > set it aligned to the corner you want
Done. Here's what it looks like in my Designer:
Now adapt above to your real form.
Ok, it appears achieving above with Designer is hard, and perhaps a bit a matter of luck of doing things just right... Designer just doesn't support doing what you want, it seems.
For clarity this is a complete source code:
QGridLayout *layout = new QGridLayout(widget);
QTextBrowser *textBrowser = new QTextBrowser();
QLabel *label = new QLabel();
label->setText("Overlaid Text");
//label gets positioned above textBrowser and is an overlay
layout->addWidget(textBrowser, 0, 0, Qt::AlignLeft | Qt::AlignTop);
layout->addWidget(label, 0, 0, Qt::AlignRight | Qt::AlignBottom);
I had the same problem but I did not manage to add Overlapping widgets in QtDesigner. Instead, I had to create the overlapping one dynamically after initializing my MainWindow.
I've got two widgets:
dataset_tableWidget (tableWidget)
spinner_dataset_tableWidget (QtWaitingSpinner)
and I wanted to make spinner_dataset_tableWidget spin over the dataset_tableWidget.
After initializing the MainWindow you can do:
#Crating QtWaitingSpinners dinamically and positioning it over the tableWidgets
dataset_tableWidget = QtWaitingSpinner(dataset_tableWidget)
dataset_tableWidget.setSizePolicy(dataset_tableWidget.sizePolicy())

Is it possible to change the colour of a QTableWidget row label?

I have a class that inherits from QTableWidget and I'm wondering if it's possible to change the colour of the row label for each row in the table?
I don't want to change the colour of any of the cells or column headings.
Thanks :)
P.S. I would like each row label to have a different colour. The motivation is that I can use these colours as a key/legend as each row in the table corresponds to a differently coloured line on a plot.
EDIT: Image illustrating the elements of the table I am referring to:
Yes it is possible but only with a slight trick. With setVerticalHeaderItem of QTableWidget you can set a QTableWidgetItem even for header rows and there you can define a background brush for each row. However most of the times the background will be ignored because the actual QStyle will override it. Setting the style of the vertical header widget to a style that doesn't change the background however does the trick.
Example:
from PySide import QtGui
app = QtGui.QApplication([])
table = QtGui.QTableWidget(4, 2)
table.show()
for i in range(0, 4):
item = QtGui.QTableWidgetItem('Text')
item.setBackground(QtGui.QColor(i*50, i*30, 200-i*40))
table.setVerticalHeaderItem(i, item)
# print(QtGui.QStyleFactory.keys())
table.verticalHeader().setStyle(QtGui.QStyleFactory.create('CleanLooks'))
app.exec_()
Yes it appears that you can do so, using the QTableWidgetItem functions such as setForeground which you pass through a QBrush object that I believe you can use the QBrush's setColor function to pass it a color. The QTableWidgetItem documentation has a lot of aesthetic-based functions so it looks like what you're looking for especially since it seems to be able to target specific cells/items on the table. If you want to look more into the QTableWidget documentation itself, here's a link to that as well.

Accessing multiple widgets

I have made a GUI using Qt Designer, I have like 20 or more lineEdit widgets, I am looking for the correct way to access all of them without having to access each one...I explain with an example in pseudocode:
This is what I DON'T want:
lineEdit1.setText("Value = 1")
lineEdit2.setText("Value = 2")
lineEdit3.setText("Value = 3")
and so on, up to
lineEdit20.setText("Value = 20")
I am looking for something like THIS:
for i in xrange(1,21):
lineEdit(i).setText("Value = whatever")
The problem is that, as far as I know, when dragging and dropping widgets, Qt Designer automatically adds a number to the end of the name...lineEdit1, lineEdit2,....so after that I do not know how to access all of them in the code.
Firstly, you don't have to accept the name that is automatically assigned in Qt Designer. Just set the objectName property to whatever is most suitable.
To iterate over groups of widgets, there are several QObject methods available.
The most powerful is findChildren which can search recursively for objects/widgets based on their class:
for child in self.findChildren(QtGui.QLineEdit):
child.setValue(value)
and also their objectName:
rgx = QtCore.QRegExp('lineEdit[0-9]+')
for child in self.findChildren(QtGui.QLineEdit, rgx):
child.setValue(value)
But a simpler technique would be to use Qt Designer to put all the widgets inside a container widget (such as a QWidget, QFrame, QGroupBox, etc), and then use the non-recursive children method to loop over them:
for index, child in enumerate(self.groupBox.children()):
child.setValue(value[index])
You might also want to consider using a QFormLayout, which provides a more structured way of doing things. This is available in Qt Designer: just drag and drop a Form Layout onto your main form and then use Add form layout row from the right-click menu to add widgets to it.
If you really want to use the QT designer, I guess your best solution is to simply add widgets to a list.
I know this is sub-optimal, but this way you will only have to do it once.
lineEditL = []
lineEditL.append(lineEdit1)
lineEditL.append(lineEdit2)
An other solution is to simply iterate the children. This is explained here, no reason to repeat.
QWidget *pWin = QApplication::activeWindow();
for( int i=1; i<=21; i++ ) {
QString strName ="LineEdit"+QString::number(i);
QLineEdit *le = pWin->findChild<QLineEdit *>(strName);
if( le ) le->setText("Value = "+Qstring::number(i) );
}

how to change the color of a QGraphicsTextItem

i have a scene with a multiple (QGraphicsTextItem)s, and i need to have control over their colors , so how to change a color of a QGraphicsTextItem ? is it possible anyway? i've been trying for 3 days until now . please help
thanks in advance
I think you can change the text color by calling the method:
void QGraphicsTextItem::setDefaultTextColor ( const QColor & col );
You have an example here.
Or looking for Diagram Scene Example in your Qt Assistant.
setDefaultTextColor(col) "Sets the color for unformatted text to col." The documentation is not clear about what "unformatted text" means. I think it means: "all portions of the contents of the item that have not been styled."
The contents is a QTextDocument.
You style a part of a document using a QTextCursor. You can't style the QTextDocument per se, only a part that is selected by a QTextCursor (but you can select the whole document.)
You can style a QTextCursor using method mergeCharFormat(QTextCharFormat)
The QTextCharFormat has methods:
foreground().setColor(QColor)
setForeground(QBrush)
setTextOutline(QPen)
Foreground is a QBrush that paints several things including "text" (but better said: the fill of characters?)
One nuance is that certain newly constructed QBrush have (default to) QBrushStyle.NoBrush, which is transparent, even if you setColor().

Categories

Resources