How to toggle QTableView column between stretch and resize - pyqt

I'm using PyQt5
I have a QTableView, which has a number of columns with varying size, it can change dynamically.
I want the table to take the maximum space it can (I have the horizontal scroll always on).
I know that setting a column setSectionResizeMode to Stretch would force a column to expand to fill the allocated space for the table, the problem is when this space is smaller than what the table needs, it just trucks the content of the column.
I'm looking to a way to do ResizeToContents is the table is larger than the space it has, or Stretch when it doesn't.
Is there such an option?

I needed to have a specific column to always show it's content, so setting the column resize mode to ResizeToContents would give me that. But I also wanted to stretch the same column if the table didn't fill all the allocated area for it in the widget, for that we could use resize mode = Stretch.
The problem that we don't have an OR option between those two modes. Also Stretch can hide the column content if it's too long.
This is what I was able to do to make this possible, hope it would help anyone.
I inherited from QTableView and added an option to select which column to stretch (self._stretch) and capture the column resize events and force this column to the required width.
class myTableView(QTableView):
# ----------------------------------------------------
def __init__(stretch_column, parent=None):
super().__init__(parent=parent)
self._table_width = 0
self._stretch = stretch_column
self._stretch_col_min_width = 0
# Use standard model:
self.model = QStandardItemModel()
self.setModel(self.model)
# Re-calculate the column width when any column width change!
self.horizontalHeader().sectionResized.connect(self._column_resize)
# ----------------------------------------------------
# ----------------------------------------------------
# Re-calculate the column width when the table size change!
def resizeEvent(self, e):
super().resizeEvent(e)
self._table_width = e.size().width()
self._column_resize()
# ----------------------------------------------------
# ----------------------------------------------------
# Calculate what the minimum width for the stretch column:
# This can be called every time we resize, but it's not recommended
# I called it after I finished filling the table data.
def calculate_column_width(self):
self._stretch_col_min_width = 0
font_metrics = self.fontMetrics()
for row in range(0, self.rowCount()):
if self.isRowHidden(row):
continue
cell_data = self.model.data(self.model.index(row, self._stretch))
cell_width = font_metrics.width(cell_data + " ") # Give it some extra chars because of the cell boarder
self._stretch_col_min_width = max(cell_width, self._stretch_col_min_width)
# ----------------------------------------------------
# ---------------------------------------------------
def _column_resize(self):
# Calculate required minimum width of the column:
# FIXME - it can be called after filling the table data, and be removed from here
self.calculate_column_width()
# Calculate all column width - excluding the stretch column:
total_width = 0
for col in range(0, self.columnCount()):
if col != self._stretch:
total_width += self.columnWidth(col)
# Add vertical header width:
total_width += self._v_header.geometry().width()
# Calculate missing area to fill the parent view:
delta = self._table_width - total_width
# Expand the stretched column to fill the table view - or force it to be the minimum required width:
self.setColumnWidth(self._stretch, max(self._stretch_col_min_width, delta))
# ---------------------------------------------------

Related

Background color for excel file with Pandas: problem with single column boundaries (for outliers)

I need to export an excel where the outliers of my dataset are highlighted in yellow. As you know, calculated with upper bound and lower bound.
I've managed to set up the function, I just can't get it to work in an iterated way so the bounds are for each column.
When I export the dataframe into an excel file, it colours the cells based on the outliers of only one variable. It doesn't work in iterated mode.
Here my code, where am I wrong?
Here I just calculate for each column the lower and the upper bound (except for Subject ID)
for col in dfm.columns.difference(['Sbj']):
Q1c = dfm[col].quantile(0.25)
Q3c = dfm[col].quantile(0.75)
IQRc = Q3 - Q1
lowc = Q1-1.5*IQR
uppc = Q3+1.5*IQR
I set the function to colour the single value based on the limit values (not iterated)
def color(v):
if v < lowc or v > uppc:
color = 'yellow'
return 'background-color: %s' % color
apply the function iteratively for each column
for col in dfm.columns.difference(['Sbj']):
df_colored = dfm.style.applymap(color)
It is obvious that something is wrong with the iteration.
Many thanks!!

Zoom couple of columns to fit page with VBA

I'm having trouble fitting my columns in Excel on a sheet.
I have a sheet with columns from A to CK (can be different per project).
I don't need to print column A, but column B has to be on all pages and next to column B has to be 3 columns. So that will make column "B,C:E" on first page, next page "B,F:H", and so on... Column B is set as title, so it will be printed on every page.
My problem is to set the scale. What I'm doing:
Take pagesize and translate to points, take off margin left and margin right = my printable area
Get the width of range("B:E") = my range to fit the page
Divide my printable area by my range to fit, multiply that with 100%, and extract 1% to make sure it will fit
The outcome in my situation is 83, but is has to be 77 to fit the page. I'll have to find other numbers I think, but I don't know how and which...
My code:
If ActiveSheet.Name = "Meterkastlijst" Then
Dim lngZoom As Long
Dim lngKolB As Long
Dim lngPagB As Long
lngKolB = ActiveSheet.Range("B:E").Width
If ActiveSheet.PageSetup.PaperSize = xlPaperA4 Then
lngPagB = CLng(Application.CentimetersToPoints(21)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
ElseIf ActiveSheet.PageSetup.PaperSize = xlPaperA3 Then
lngPagB = CLng(Application.CentimetersToPoints(29.7)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
End If
If lngPagB <> 0 And lngKolB <> 0 Then
lngZoom = ((lngPagB / lngKolB) * 100) - 1
With ActiveSheet.PageSetup
.Zoom = lngZoom
End With
End If
End If
Different widths:
Column B: 45 (319 pixels) -> in Excel, set with VBA
Column C: 15 (109 pixels) -> in Excel, set with VBA
Column D: 30 (214 pixels) -> in Excel, set with VBA
Column E: 20 (144 pixels) -> in Excel, set with VBA
Column B-E: 589 points -> with VBA
Page: 21 centimeters (595 points)
Margins (left & right): 1.8 centimeters (50.4 points)
Print area: 595 - 101 (100.8) = 494 points
With numbers above it calculates 83%, but then it doesn't fit, when I set it manually to 77% it does fit, but how can I get this number with VBA? I don't understand the column widths, what I see in Excel and how I set it in VBA (45+15+30+20) is different from what VBA tells me it should be (589)...
Column Width Units
Column width is measured in Characters, Points, Centimeters / Inches, Pixels, ...
Column width in Characters
If you set a column width by manual value input or by mouse, you see the "amount of standard font number characters". Please refer to Microsoft support for details.
This value can be read and written in VBA: .Range.ColumnWidth = 10.78.
The maximum value is 255.
Column width in Points
This is an internal value not shown in GUI during manual resize of a column.
It corresponds to 72 points per inch.
In VBA it can only be read: .Range.Width
Column width in Pixels
Excel shows the column width in pixels (in parentheses) during manual resize of a column width in normal view. This value can not be read or written directly in VBA.
Column width in Centimeters or Inches
During manual resize within the page layout view Excel shows column width in centimeters (or inches) instead of pixels.
Only this value depends on print zoom level!
The measurement unit itself can be read in VBA:
Application.MeasurementUnit ' 0 = xlInches, 1 = xlCentimeters, 2 = xlMillimeters
Conversion Formulas
By this you may check or verify all values in your environment:
Dim ScreenResolution As Double
Dim ColumnWidthChars As Double
Dim ColumnWidthPoints As Double
Dim ColumnWidthPixels As Double
Dim ColumnWidthInches As Double
Dim ColumnWidthCentimeters As Double
ScreenResolution = 120 ' normal (96 dpi) or large (120 dpi)
ColumnWidthChars = ActiveSheet.Columns(1).ColumnWidth
ColumnWidthPoints = ActiveSheet.Columns(1).Width
ColumnWidthPixels = (ColumnWidthPoints / 72) * ScreenResolution
ColumnWidthInches = ColumnWidthPoints / 72 * ActiveSheet.PageSetup.Zoom / 100
ColumnWidthCentimeters = ColumnWidthInches * 2.54
Debug.Print ColumnWidthChars, ColumnWidthPoints, ColumnWidthInches, _
ColumnWidthCentimeters, ColumnWidthPixels
ScreenResolution may be retrieved with API function GetDeviceCaps(hDC, 88)
Rounding Effects
Excel stores the character-based .Range.ColumnWidth with decimals for each relevant column in the workbook file. If you set it to 100, it is stored as e. g.
<cols><col min="1" max="1" width="100.77734375" customWidth="1"/></cols>
After reopening this file, the reported .ColumnWidth is 100 without decimals.
If you set a large column width and switch between normal view and page layout view, then you may register difference of about 2% between the measures (.Range.Width and pixels suddenly change) - but all values still correspond to each other according to above formulas.
Display Scaling Dependency
All different column width values are independent of Excel's view zoom level and/or Windows 10 display scaling.
Print Zoom Dependency
Only the inch- and centimeter values change, if you change the print zoom level.
But you get more or less columns i. e. amount of points on your paper.
Excel measures .PageSetup.Leftmargin in points (with a scale of 72 points per inch). This corresponds to .Range.Width which is also measured in points.
Example: If I set both paper margins to 5.5 cm, then the resulting A4 paper width of 10 cm holds e. g. two columns with a total .Width of appr. 283 points which corresponds to 72 points/inch.
If I set the print zoom to 83 percent a .Width of appr. 340 points is maximum, and at a print zoom of 30 % it's almost 943 points.
Print Scaling
The calculation of a print zoom factor is
WorkSheet.PageSetup.Zoom = (PageWidthInPoints / AllColumnsWidthInPoints) * 100
Your calculation seems to be correct, but I would subtract at least 2 % (see rounding effects above).

Spotfire Table Visualization column width

Is there a way to set Spotfire Table visualization column width either through Java or Python script. i can able to change the column width manually but whenever the value changes through property control it reset again. I need to set constant column width. Thanks in advance.
from Spotfire.Dxp.Application.Visuals import TablePlot
# Tab is the (Visualization) parameter passed to the script specify the table to work on
dataTable= Tab.As[TablePlot]().Data.DataTableReference
# Get a handle to the Table plot
table = Tab.As[TablePlot]()
# Get the ColumnCollection for the Table plot
columns = table.TableColumns
# Size all of the columns
for x in columns:
x.Width = 200
good question! you can add an IronPython script (I don't believe it's possible to do this using Javascript unless you are some kind of wizard, or otherwise hate yourself :) to do this pretty simply.
I'll put the examples all in one code snippet, but obviously you would only want to do one of these loops at a time. the snippet expects a parameter called viz whose value is the TablePlot visualization you wish to modify.
from Spotfire.Dxp.Application.Visuals import TablePlot
v = viz.As[TablePlot]()
# increase all column widths by 10 pixels
for col in v.Columns:
col.Width = col.Width + 10
# set all column widths to 100 pixels (the default value)
for col in v.Columns:
col.Width = 100
# set the width of a specific column to 50 pixels
for col in v.Columns:
if col.Name == "My Column":
col.Width = 50

How to resize the widget that hold a QTableView?

I have a QTableView inside a layout itself inside a Widget.
How I can set the Widget size after the call of tableView.resizeColumnsToContents() in order to have the same size of the table (and does not need a scrollbar )
Thanks
If I understand properly what you want is to adjust the horizontal size of the container widget to the size of the table contents (which is not necessarily the table size). The following method works for me with a small table of 20 rows and 3 columns:
ask the table model for the total number of columns (it should be returned by your implementation of the columnCount method)
ask the view for the width of every column using the columnWidth method and compute the total width of the columns
finally resize your container widget taking into account the total width of columns, the width of the table vertical header and the autoscroll margin
So the code would look like:
my_table_view.resizeColumnsToContents()
w = 0
for c in range(my_table_model.columnCount()):
w = w + my_table_view.columnWidth(c)
container_widget.resize(w + my_table_view.verticalHeader().width() + my_table_view.autoScrollMargin()*1.5, container_widget.size().height())
As I said, I'm assuming that you want to resize your widget horizontally.

Setting column width in RTF

I have what I hope is a simple question !
I am generating a simple RTF table that is subsequently opened in MS Word. The table is generating fine but the column widths are a little small and causing some word wrapping (not what I want).
The RTF code I generate is for a two line, three column table and is of the form:
\trowd \trautofit1
\intbl
\cellx1
\cellx2
\cellx3
{a\cell b\cell c\cell }{\trowd \trautofit1
\intbl
\cellx1
\cellx2
\cellx3
\row}
\trowd \trautofit1
\intbl
\cellx1
\cellx2
\cellx3
{d\cell e\cell f\cell }{\trowd \trautofit1
\intbl
\cellx1
\cellx2
\cellx3
\row}
What do I need to add to set a column width ? I have tried altering the column width in word and then examining the output but it is a little obscure to say the least !
The control words you are looking for are \clwWidthN and \clftsWidthN
Microsoft RTF Specification v1.9.1:
- \clwWidthN
Preferred cell width. Overrides \trautofitN.
- \clftsWidthN
Units for \clwWidthN:
- 0 : Null. Ignore \clwWidthN in favor of \cellxN (Word 97 style of determining cell and row width).
- 1 : Auto, no preferred cell width, ignores \clwWidthN if present; \clwWidthN will generally not be written, giving precedence to row defaults.
- 2 : Percentage (in 50ths of a percent).
- 3 : Twips.
So, in your case, you could just use \clftsWidth1 (automatically set width) or set the preferred percentages yourself e.g. \clwWidth2\clwWidth2500 (2500 = 50%)
Auto width
\trowd \trautofit1
\intbl
\clftsWidth1\cellx1
\clftsWidth1\cellx2
\clftsWidth1\cellx3
{a\cell b\cell c\cell }
40% - 30% - 30%
\trowd \trautofit1
\intbl
\clftsWidth2\clwWidth2000\cellx1
\clftsWidth2\clwWidth1500\cellx2
\clftsWidth2\clwWidth1500\cellx3
{a\cell b\cell c\cell }
The problem is in that you have set very small width for column:
\cellx1
\cellx2
\cellx3
To set width for column in RTF there is a keyword '\cellxN', where N - is column width in twips.
15 twips is 1px.
So if you want to create a simple RTF table with 1 row and 3 columns, 100px each, use this syntax:
\trowd\cellx1500\cellx3000\cellx4500
\intbl A\cell B\cell C\cell\row
You will get a simple table by 300px, 3 columns - 100px each, with invisible borders.
Cheers,
Max
You need to either use cellx0, so that autofit tag applies, or explicity set the number to the number of twips from the left border. In your example, you use 1 2 and 3 which is explicity setting the column widths to be very skinny. For example, something like:
\cellx5125
\Cellx6000
\Cellx8000
Note that these numbers are offsets from the left margin.
If you are going to do any RTF, I highly recomend the RTF Pocket Guide from O'Rielly
Check this link
http://joseluisbz.wordpress.com/2014/04/26/working-rtf-html-css-and-script-files-with-my-own-packages-java-and-php/
you can to make your own file.
TblData = new RTFTable(4,4); //4 Columns, 4 Rows
TblData.setWideCols(1000); //Width of 2000 to put all columns
TblData.setWideCol(0,3000); //Width of 3000 to Column 0

Resources