In a QVBoxLayout added two QTableViews. The first one has constant number of rows (2), the second one has many. The goal is to make the second table begin just after last row in the first table.
I tried change QSizePolicy, setMinimumSize() - nothing helps. Here is sample of code:
layout = QVBoxLayout()
first_table = QTableView()
second_table = QTableVew()
first_table.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
second_table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
layout.addWidget(first_table)
layout.addWidget(second_table)
It looks like it uses sizeHint() no matter of setMinimumSize(h, v) values. How to make the first table do not show space without rows?
You might want to do the following:
layout = QVBoxLayout()
first_table = QTableView()
second_table = QTableVew()
layout.addWidget(first_table)
layout.addWidget(second_table)
layout.addStretch(1); // <--- to keep both tables together.
Related
I'm trying to understand a strange (to my understanding) behavior when trying to insert a column in a treeview at index 0.
While I understand that this is not a suggested course of action, the result still puzzles me.
If I add a child to an item that is not in the first column, it is obviously not shown, since only children of the root index in first column are expanded; but it seems that when the new column is inserted, the existing children of the previous first column are "inherited" by the new item.
class TreeTest(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
insertColBtn = QtWidgets.QPushButton('insert column')
layout.addWidget(insertColBtn)
insertColBtn.clicked.connect(self.insertColumn)
insertColAfterBtn = QtWidgets.QPushButton('insert child and insert column')
layout.addWidget(insertColAfterBtn)
insertColAfterBtn.clicked.connect(self.insertColumnAfter)
removeColBtn = QtWidgets.QPushButton('remove column')
layout.addWidget(removeColBtn)
removeColBtn.clicked.connect(self.removeColumn)
self.tree = QtWidgets.QTreeView()
layout.addWidget(self.tree)
self.model = QtGui.QStandardItemModel()
self.tree.setModel(self.model)
self.parent1 = QtGui.QStandardItem('parent 1')
self.parent2 = QtGui.QStandardItem('parent 2')
self.model.appendRow([self.parent1, self.parent2])
self.child = QtGui.QStandardItem('child of parent 1')
self.parent1.appendRow(self.child)
self.parent2.appendRow(QtGui.QStandardItem('child of parent 2'))
self.tree.expandAll()
self.tree.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
def insertColumn(self):
newParent = QtGui.QStandardItem('new parent')
self.model.insertColumn(0, [newParent])
newChild = QtGui.QStandardItem('new column child')
self.parent1.appendRow(newChild)
def insertColumnAfter(self):
newParent = QtGui.QStandardItem('new parent')
newChild = QtGui.QStandardItem('new column child')
self.parent1.appendRow(newChild)
self.model.insertColumn(0, [newParent])
def removeColumn(self):
self.model.removeColumn(0)
This is the what appears at the beginning (the "child of parent 2" is obviously hidden):
Then I insert a new first column, then I add a child to the previous parent (which is now on the second column); as you can see, the previous child is now apparently become a child of the new item, while the new child item is not visible:
Finally, I try to remove the first column, and the previously added child is now visible:
Strangely enough, if a new child item of the previous first column is added before inserting the new column (insertColumnAfter()), it works "as expected", probably due to the delay item views usually have before laying out the items after a model change:
Again, I realize this is not the "standard" way to deal with a tree model.
Still, I'd like to understand what's going on here, whether it's an expected behavior (probably by design, even if not perfect) or some kind of bug.
I've been able to reproduce this behavior with PyQt up to 5.12.4, I can't test with newer versions.
I have a .docx template with an empty table, where I am adding values:
def manipulate_table():
table = doc.tables[0]
table.cell(0, 0).text = 'A'
table.cell(0, 1).text = 'B'
table.cell(0, 2).text = 'C'
table.cell(0, 3).text = 'D'
After adding these values, the the table attribute "Centered" is gone, which is standard behaviour.
How can I loop through my table and center all values again? I've already Googled, but found nothing helpful. E.g.: does not work:
for cell in ....????:
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcVAlign = OxmlElement('w:vAlign')
tcVAlign.set(qn('w:val'), "center")
tcPr.append(tcVAlign)
I appreciate all your help.
The .text property on a cell completely replaces the text in the cell, including the paragraph(s) that were there before.
The "centered" attribute is on each paragraph, not on the cell. So you need to do something like:
from docx.enum.text import WD_ALIGN_PARAGRAPH
cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
to each of the "new" paragraphs (assigning to .text will leave you with exactly one in each cell).
According to the docs
public Table(int numColumns,
boolean largeTable)
Constructs a Table with specified number of columns. The final column widths depend on selected table layout. Since 7.0.2 table layout algorithms were introduced. Auto layout is default, except large tables. For large table fixed layout set implicitly. Since 7.1 table will have undefined column widths, that will be determined during layout. In oder to set equal percent width as column width, use UnitValue.createPercentArray(int)
I render a large table using https://developers.itextpdf.com/examples/tables/clone-large-tables
Is there a way to define autoLayout? Maybe after adding the first row, get the cell widths and set them on the table, but that doesn't seem possible, because the column widths are null because I am using the constructor with number of columns.
Or adding some sort of autoLayout when end page is reached.
I don't want to define the widths for the columns because we have lots of tables.
First of all I would like to mention that auto layout requires the content of the whole table. The content is used when calculating the column widths. But you are using large table, which probably means you have a lot of data and you don't want to keep everything in memory (if that's not the case, just don't use large tables).
Thus, all you can do is calculate an approximation of the automatic column widths given some initial cells. Basically, it is possible to implement your first idea, however, it takes some code to be written. But if you have very different content in cells across different rows (e.g. images vs inner tables vs some text), then this method might not work very well because as I said, to estimate column widths well you need all the content.
Please also bear in mind that this approach is quite dirty and might not work for some corner cases. But it does solve the goal and frees you of the necessity to define column widths.
To describe the solution in a few words, we take cells of several initial rows, add them to a temporary table and layout it (estimate positions etc), without actually drawing it anywhere. Then we extract the cell widths from the layout step information and can use them for the large table constructor.
The method estimating column widths looks like this:
private UnitValue[] estimateWidths(Document document, Cell[][] cells) {
int numOfColumns = cells[0].length;
Table table = new Table(numOfColumns);
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
table.addCell(cells[i][j]);
}
}
LayoutContext context = new LayoutContext(document.getRenderer().getCurrentArea().clone());
TableRenderer tableRenderer = (TableRenderer)table.createRendererSubTree();
LayoutResult result = tableRenderer.setParent(document.getRenderer()).layout(context);
if (result.getStatus() == LayoutResult.PARTIAL) {
tableRenderer = (TableRenderer) result.getSplitRenderer();
}
UnitValue[] widths = new UnitValue[numOfColumns];
List<IRenderer> subList = tableRenderer.getChildRenderers().subList(0, numOfColumns);
for (int i = 0; i < subList.size(); i++) {
IRenderer cell = subList.get(i);
widths[i] = UnitValue.createPointValue(cell.getOccupiedArea().getBBox().getWidth());
}
return widths;
}
So assuming you have a Cell[][] cells array of cells for initial couple of rows (can be one row as well, but the more the better), where cells[i][j] refers to the cell at row i and column j, you can create your large table like this:
Table table = new Table(estimateWidths(doc, cells), true);
But don't forget to explicitly add cells from cells array to the large table before adding new content.
I have three part in my PDF generating document using iTextSharp library.
The Header and footer I am printing using OnEndPage() of PdfPageEventHelper class. The header and footer printing well in all pages.But problem in printing large table content from middle of the page.
Now, I am facing problem when I have more that 100 table rows content to print on middle of the page.
On first page (middle of the page) I am printing table with more than 100 rows, but in this case it leave the first page empty and start printing table content on second page. Here is my table that I am trying to print on first page
PdfPTable table = new PdfPTable(5);
table.HeaderRows = 1;
table.SplitLate = false;
table.SplitRows = false;
table.SetTotalWidth(new float[] { 100, 75, 75, 75, 75 });
table.LockedWidth = true;
for (int i = 0; i < 150; i++)
{
PdfPCell cell = new PdfPCell(new phrase());
cell.Colspan = 5;
table.AddCell(cell);
}
I am using iTextSharp version: 5.4.5.0
Is there any configuration need to do, that will prevent page break?
But I am getting actual result in this format
Allow me to comment on these two lines:
table.SplitLate = false;
table.SplitRows = false;
The first line tells iTextSharp what it should do if a row doesn't fit a page. If you set this value to false, rows will be split late. For instance: you have a big row that doesn't fit the current page. In that case, the row will be forwarded to the next page. If it still doesn't fit the page, then another decision needs to be made: should the row be split or not?
The second line gives iTextSharp the answer to that question. If the value of SplitRows is true, then the row will be split. If the value is false, the row will be dropped. Allow me to quote the official documentation (p115 of "iText in Action - Second Edition"):
Ths is a dangerous line, because now not one row will be split. Rows that are too high to fit on a page will be dropped from the table!
I have the feeling that you want all the rows to show up in the table, so I suggest that you change the two lines I mentioned to:
table.SplitLate = true;
table.SplitRows = true;
Actually: why don't you just remove those two lines? The default value of SplitLate and of SplitRows is true.
Same thing happened to me using nested tables.
I solved this problem using .SplitLate = false; in the first table :)
I am little bit confuse.
I am working with QTreeView as model I assigned QSortFilterProxyModel.
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qsortfilterproxymodel.html
//treeview
self.ProxyView = QtGui.QTreeView(self.centralwidget)
//model
self.ProxyModel = QtGui.QSortFilterProxyModel(self)
self.ProxyModel.setSourceModel(QtGui.QStandardItemModel(0, 3, self))
//assign model to tree
self.ProxyView.setModel(self.ProxyModel)
On button click I want to add row to this tree.
Here is my slot
def pushButton_addRow(self):
self.ProxyModel.insertRow(0)
self.ProxyModel.setData(self.ProxyModel.index(0,0), "hi")
It doesnt work, it works only for first row, then I added empty rows. But wenn I fill second cell it works.
self.ProxyModel.setData(self.ProxyModel.index(0,1), "hi")
Any Idea?
Maybe your new QModelIndex has wrong parent()?