How to print a QTableView
One way to do it is to dump the table contents into a QTextDocument
, and then print that.
The following demo uses a simple text-table, but html could be used to get more sophisticated formatting:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self, rows, columns):
QtGui.QWidget.__init__(self)
self.table = QtGui.QTableView(self)
model = QtGui.QStandardItemModel(rows, columns, self.table)
for row in range(rows):
for column in range(columns):
item = QtGui.QStandardItem('(%d, %d)' % (row, column))
item.setTextAlignment(QtCore.Qt.AlignCenter)
model.setItem(row, column, item)
self.table.setModel(model)
self.buttonPrint = QtGui.QPushButton('Print', self)
self.buttonPrint.clicked.connect(self.handlePrint)
self.buttonPreview = QtGui.QPushButton('Preview', self)
self.buttonPreview.clicked.connect(self.handlePreview)
layout = QtGui.QGridLayout(self)
layout.addWidget(self.table, 0, 0, 1, 2)
layout.addWidget(self.buttonPrint, 1, 0)
layout.addWidget(self.buttonPreview, 1, 1)
def handlePrint(self):
dialog = QtGui.QPrintDialog()
if dialog.exec_() == QtGui.QDialog.Accepted:
self.handlePaintRequest(dialog.printer())
def handlePreview(self):
dialog = QtGui.QPrintPreviewDialog()
dialog.paintRequested.connect(self.handlePaintRequest)
dialog.exec_()
def handlePaintRequest(self, printer):
document = QtGui.QTextDocument()
cursor = QtGui.QTextCursor(document)
model = self.table.model()
table = cursor.insertTable(
model.rowCount(), model.columnCount())
for row in range(table.rows()):
for column in range(table.columns()):
cursor.insertText(model.item(row, column).text())
cursor.movePosition(QtGui.QTextCursor.NextCell)
document.print_(printer)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window(25, 2)
window.resize(300, 400)
window.show()
sys.exit(app.exec_())
Print all visible rows in QTableView in c++
You can get the current line number through the value()
of the verticalScrollbar
, and you can also get the number of displayable lines through pagestep()
.
This is my code ,you can try it:
void TesWidget::onbtnClicked()
{
int start_index = ui.tableView->verticalScrollBar()->value();
int page_cnt = ui.tableView->verticalScrollBar()->pageStep();
int end_index = start_index + page_cnt;
int row_cnt = model_->rowCount();
int col_cnt = model_->columnCount();
QString text;
for (int i = start_index; i < row_cnt && i <= end_index; i++)
{
for (int j = 0; j < col_cnt; j++)
{
text.append(QStringLiteral("%1 ").arg(model_->item(i,j)->text()));
}
text.append("\n");
}
qDebug() << text;
}
Printing QTableView using render method
Ok, here is my solution. Would be nice to hear your opinion.
PrintTableModel* pTableModel = new PrintTableModel();
QTableView* pTableView = new QTableView;
pTableView->setModel(pTableModel);
int width = 0;
int height = 0;
int columns = pTableModel->columnCount();
int rows = pTableModel->rowCount();
pTableView->resizeColumnsToContents();
for( int i = 0; i < columns; ++i ) {
width += pTableView->columnWidth(i);
}
for( int i = 0; i < rows; ++i ) {
height += pTableView->rowHeight(i);
}
pTableView->setFixedSize(width, height);
pTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
pTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
This code helped me. To print the table correctly, you just can perform a render call:
pTableView->render(printer);
Printing QTableView with vertical and horizontal headers
If you want to print the headers you must add them as shown in the following code:
void Snapshot_finance::on_pushButton_print_clicked()
const QString format("<td>%1</td>");
QString html;
QAbstractItemModel *md = ui->tableView->model();
html = "<html><body><table border=\"0\">";
html += "<td></td>";
for(int column = 0; column < md->columnCount();
column++) {
QString data = md->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
html += format.arg(data);
}
for(int row = 0; row < md->rowCount() ; row++) {
html += "<tr>";
QString data = md->headerData(row, Qt::Vertical, Qt::DisplayRole).toString();
html += format.arg(data);
for(int column = 0; column < md->columnCount();
column++) {
QString data = md->index(row, column).data(Qt::DisplayRole).toString();
html += format.arg(data);
}
html += "</tr>";
}
html += "</table></body></html>";
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer);
if(dialog->exec() == QDialog::Accepted) {
QTextDocument document;
document.setHtml(html);
document.print(&printer);
}
}
TableView:
Part of PDF
The code that is implemented for the test can be found in the following link.
Reduce excessive painting when populating QTableView in batches
Qt models provide a couple of useful functions:
canFetchMore(parent)
, which says if the model can load more data (for a given parent);fetchMore(parent)
tells the model to do load more data (but the model decides the amount of the "more");
Those functions are called by item views so that when they can request the model if there's more data to load whenever the user has scrolled to the end (usually, at the bottom) and eventually tell the model to do the fetching.
Considering the above, what you need to do is to implement a model that starts with a specified minimum amount of data, provides both fetching methods to load further data, and then add a timer to the view to request further fetching whenever it's possible, unless the current state()
is EditingState
or the model cannot fetch more data.
Since your code is too complex for an answer, I created a simpler example to explain the concept; the second columns shows when the index has been fetched starting from the moment the model has been created:
from PyQt5 import QtCore, QtWidgets
class TestModel(QtCore.QAbstractTableModel):
totalRowCount = 1980
currentRowCount = 25
fetchAmount = 25
def __init__(self):
super().__init__()
self.eTimer = QtCore.QElapsedTimer()
self.eTimer.start()
self.times = {
r:0 for r in range(self.currentRowCount)
}
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return ('Item', 'Loading time')[section]
return super().headerData(section, orientation, role)
def rowCount(self, parent=None):
return self.currentRowCount
def columnCount(self, parent=None):
return 2
def canFetchMore(self, parent=None):
return self.currentRowCount < self.totalRowCount
def fetchMore(self, parent=None):
maxRow = min(self.totalRowCount, self.currentRowCount + self.fetchAmount)
self.beginInsertRows(QtCore.QModelIndex(), self.currentRowCount, maxRow - 1)
t = self.eTimer.elapsed() * .001
self.times.update({r:t for r in range(self.currentRowCount, maxRow)})
self.currentRowCount += self.fetchAmount
self.endInsertRows()
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if index.column() == 0:
return 'Item at row {}'.format(index.row() + 1)
return self.times[index.row()]
def flags(self, index):
return super().flags(index) | QtCore.Qt.ItemIsEditable
class TestTable(QtWidgets.QTableView):
def __init__(self):
super().__init__()
self.resize(640, 480)
self._model = TestModel()
self.setModel(self._model)
self.horizontalHeader().setSectionResizeMode(
QtWidgets.QHeaderView.Stretch)
self.fetchTimer = QtCore.QTimer(
interval=1000, singleShot=True, timeout=self.fetchMore)
self.fetchTimer.start()
def fetchMore(self):
if self.model().canFetchMore():
if self.state() != self.EditingState:
self.model().fetchMore()
self.fetchTimer.start()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
w = TestTable()
w.show()
app.exec_()
Note: the parent argument for canFetchMore
and fetchMore
is mandatory, just like rowCount
and columnCount
.
Obviously, if your model requires some time to fetch the actual data and finally insert new indexes (for instance, a remote database or network requests), you need to implement that with a further delay timer to "queue" the fetch requests.
You can create another single-shot timer in the model, and then push the fetching (beginInsertRows
and endInsertRows
) whenever the model is able to do that, even using a separate thread.
As a further and unrelated suggestion, please try to put more efforts in making your examples more minimal: your question is about general updating of a view with multiple items, all delegate aspects and resizing of items are completely unnecessary for that, and they just become an annoying and unnecessary distraction from what we should be focusing into.
display data from MySQL database to qtableview python pyqt5
If you want to display the data automatically, do not use method because if you want you should call it. The code will be messy but it will work for you.
Months ago I had create a CRUD app using tablewidget, but if you want to display just the data, you should use tableview.
This code will work for you if you want use qtablewidget, but if you use tableview you should create model or use pyqt predefined classes
try:
connection = mc.connect(host=cr.host, user=cr.user, password=cr.password, database=cr.database)
cur = connection.cursor()
cur.execute("SELECT * FROM student")
result = cur.fetchall()
self.list.setRowCount(0)
print("ff")
for row_number, row_data in enumerate(result):
self.list.insertRow(row_number)
for column_number, data in enumerate(row_data):
self.list.setItem(row_number, zcolumn_number, QTableWidgetItem(str(data)))
except mc.Error as e:
print(e)
Note: list
is the name of the table
Related Topics
How to Convert from Lpctstr to Std::String
Portable End of Line (Newline)
C++ Calculating More Precise Than Double or Long Double
Static Variable in the Class Declaration or Definition
Is Maximum_Wait_Objects Really 64
Move Out Element of Std Priority_Queue in C++11
When Would You Use an Array Rather Than a Vector/String
C++ Static Const Access Through a Null Pointer
Conflict Between Copy Constructor and Forwarding Constructor
Opencv 2.4.3 iOS Framework Compiler Trouble Recognising Some C++ Headers
How to Enforce C++ Compiler to Use Specific Crt Version
How to Create a Std::Set of Structures
Efficient Multiply/Divide of Two 128-Bit Integers on X86 (No 64-Bit)
Pointer Array and Sizeof Confusion
Multiple Inheritance: Unexpected Result After Cast from Void * to 2Nd Base Class