I need to display data using the PyQt class QTableWidget. But there could be dozens of thousand lines. Displaying the whole sheet makes the appli to hang...
So I found a solution consisting on loading data (meaning that the sheet is created) but hidding most of the rows and, when moving the scroll bar, show new rows and hidding previous ones.
In the bellow code, I setted self.rowsShown = 50 and at the init the lines from 1 to 50 are shown. And I previously did self.verticalScrollBar().actionTriggered.connect(self.refreshDisplay).
So the code is:
def refreshDisplay(self):
"""
This is to refresh the display when the scrollbar is moved
"""
# Minimum is reached and a previous row exists
if self.verticalScrollBar().value() <= self.verticalScrollBar().minimum() and self.isRowHidden(self.firstRowShown-1):# Minimum is reached and a previous row exists
for row in xrange(self.lastRowShown-1, self.lastRowShown):
self.hideRow(row)
self.lastRowShown -= 1
for row in xrange(self.firstRowShown-1, self.firstRowShown):
self.showRow(row)
self.firstRowShown -= 1
# Maximum is reached and a next row exists
if self.verticalScrollBar().value() >= self.verticalScrollBar().maximum() and self.isRowHidden(self.lastRowShown+1):
for row in xrange(self.firstRowShown, self.firstRowShown+1):
self.hideRow(row)
self.firstRowShown += 1
for row in xrange(self.lastRowShown, self.lastRowShown+1):
self.showRow(row)
self.lastRowShown += 1
This is working very well when I use the roll of the mouse or click on buttons of the scrollbar. But when I grab the slider or use the keypad to move the case selected, I'm blocked in the area shown.
Moreover, the size of the scrolling area correspond to the rows shown only. I would like to redifine it to set my own bar (for example with a size based on the real number of lines), so that I can move fastly to another part of the sheet. But the size of the scroll bar is always updated with the number of lines shown.
So, what I expect from you is to help me to resolve this two issues, OR give me another idea for displaying such huge sheet. Maybe I missed a module or class that already bear this functionnality of loading/showing lines whilemoving the cursor.
Thanks
I have written a tool that displays 10^6+ lines in an Excel-like table without resource problems. The solution is to use QTableView and QAbstractTableModel. You have to derive from QAbstractTableModel and implement the necessary functions it requires you to implement (I remember headerData and data, but I think there are more). You then plug the model into your view by doing view.setModel(model). More information how this is done can be found here.
Related
I have searched for answers to this question and always get sent back to printing the selection with print(var.get()).
I don't want to print the selection, but to store it in a variable that I can then use in my code.
For more context, I'm making a simple gui to filter data frames. There are a bunch of dropdown menus from which the user selects specific features. I then want to get all of those features to filter down my data frame to a single entry.
The code snippet below shows what I'm trying, but I don't know how to get the data frame that the function filter_df returns (the data frame df is defined before).
I'd also need to use the value of each previous dropdown menu to remove all the impossible feature values (as in, no entry has both the previous value and the one I select after).
Is any of this possible, or are there elements I'm going to have to find a way around ?
I thank any and all answers in advance, this website is what makes the (or at least my) coding world go round.
app = tk.Tk()
app.geometry('100x200')
detail_app_str = tk.StringVar(app)
detail_app_str.set('Select Scope')
detail_dropedown = tk.OptionMenu(app, detail_app_str, *feature_values)
detail_dropedown.config(width=90, font=('Helvetica', 12))
detail_dropedown.pack(side="top")
def filter_df(*args):
filtered_df = df[(df['A'] == int(detail_app_str.get()))]
return filtered_df
detail_app_str.trace_add("write", filter_df)
I've been trying to figure out how to clear tableWidget so i can add new content. The snippet below shows the widget and how the information is added. However, anytime i refresh it, instead of clearing the screen it rather add more information.
Any help will be appreciated.
Thanks
def addNewContent(results):
header = self.tableWidget.horizontalHeader()
self.tableWidget.clearContents()
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
numrows = len(results)
numcols = len(results[0])
self.tableWidget.setRowCount(numrows)
self.tableWidget.setColumnCount(numcols)
for row in range(numrows):
for column in range(numcols):
self.tableWidget.setItem(row, column, QTableWidgetItem((str(results[row][column]))))
addNewContent(results)
I've searched a lot for this problem the only solution that I came up with, was to call model.clear() and then setting the header labels once again
I think problem is in the variable result i believe its a list so all what you have to do is reinitialize it then append it with the new values somewhere in your code
I'm currently developing a cross-platform app (current developing it's under Ubuntu 18.10 and Windows 10) with PyQT 5.13.1 on Python 3.6/3.7. I'm using a QTableWidget that I've initialized in this way:
myTable = QTableWidget()
myTable.setSelectionBehavior(QAbstractItemView.SelectRows)
myTable.setSelectionMode(QAbstractItemView.SingleSelection)
myTable.setAlternatingRowColors(True)
At app's start, my table has two columns but is empty (no rows) and I've a button to add rows one by one. When I do this the first time, the first row is added and it shows with the first cell with a sort of light blue highlight (in both Ubuntu and Windows) and the second cell without it, as in this screenshot:
If I click on any of those cells, the entire row is selected and shows a blue background, accordingly with the setSelectionBehavior initialization. If I CTRL+Click that selected row, it got deselected and goes back with the first cell active/highlighted and the second not. My question is: is there a way to completely remove that highlight (what I'd prefer) or to extend it also to adjacent cell? I've read around that one possible solution wuold be to disable table's focus, but I wish to avoid such a solution.
Thank you all in advance!
The currentIndex exists even when no index is selected, and by default it is highlighted. So to eliminate this behavior you can use a delegate to eliminate that behavior:
class Delegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
option.state &= ~QtWidgets.QStyle.State_HasFocus
delegate = Delegate(myTable)
myTable.setItemDelegate(delegate)
I'd like to have a QTableWidget that has 2 'header' rows. Essentially I'd like to have the top 2 rows of the table not scroll vertically. For example:
Header 1 | Header 2
__________________
Header 3 | Header 4
__________________
Data | Data
__________________
Data | Data
__________________
Data | Data
__________________
Data | Data
__________________
I'd like to prevent any of the 4 headers (first two rows) not scroll off the screen as the user scrolls down.
I don't see anyway in Qt to add additional header rows or prevent scrolling of a single row. Maybe there is a tricky way to do this by having 2 actual tables and 1 of those tables having a single row which is a header?
I found a way to do this albeit in a somewhat obscure way. I did find a great example on how to do something similar, but with columns instead of header rows.
http://doc.qt.nokia.com/4.7-snapshot/itemviews-frozencolumn.html
I created two tables, one for the header rows and one for the data. I then hid the horizontal headers for the data table, set the margins/spacing for everything to 0. This squished the tables close enough together to look like a single table.
Make sure to hide the horizontal scroll bars for each individual table and then adding a new scrollbar that connected the two hidden scroll bars. So, when the user scrolls with the stand-alone scrollbar it triggers events on the 'real' hidden scroll bars. This way users can only have a single scrollbar to interact with.
I also had to catch all the signals from the QHeaderView class
and make sure to apply the changes requested by the signals to both tables at the same time.
The trickest part was making sure the width of the vertical header items were the same length in both tables. The width of a vertical header item gets set on an event called resizeEvent, http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qwidget.html#resizeEvent. So I had to override this method in my class to set the headers on both tables to the same width.
Code:
def resize(self):
"""
Called when we know the data table has been setup by Qt so we are
guaranteed that the headers now have a width, etc.
There is no other way to guarantee that your elements have been sized,
etc. by Qt other than this event.
"""
# Make the width of the vertical headers on the header table the same
# size as the initialized width of the data table (data table widths
# are setup automatically to fit the content)
width = self._data_table.verticalHeader().width()
self._header_table.verticalHeader().setFixedWidth(width)
Override the selectAll() method so when a user clicks the corner button, if enabled, all data in both tables will be selected:
Code:
def selectAll(self):
"""Select all data in both tables"""
for table in [self._header_table, self._data_table]:
for row in xrange(table.rowCount()):
for col in xrange(table.columnCount()):
item = table.item(row, col)
table.setItemSelected(item, True)
I have a PDF I am generating using ReportLab. I am using the standard TableOfContents flowable, but am trying to split it up into two columns, so it will all fit on the first page. the content will only ever be on one level, so I am not worried about odd-looking indentations.
Right now I have the PageTemplate using 2 Frames to create 2 columns on the first page. I get a
LayoutError: Flowable <TableOfContents at 0x.... frame=RightCol>...(200.5 x 720) too large on page 1 in frame 'RightCol'(200.5 x 708.0*)
Any ideas?
Well, color me embarrassed.
For anyone else having this problem, check your DocTemplate for allowSplitting. The default is 1, but I had changed mine to 0 and that was the reason.
*facepalm*