QTextTable move QTextCursor to a determinated Cell - qt

I have a QTextTable, I do some actions in the table and I want two things:
Return QTextCursor to cell (0,0)
Or move QTextCursor to cell (row, columnn)
How can I do?

For the given table object of type QTextTable get desired cursor:
auto tableCell = table->cellAt(row, column);
auto cursor = tableCell.firstCursorPosition();
then setTextCursor within edited QTextEdit object.

Following #ekhumoro and #retmas suggestion I do this:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QTextCursor
#### EKHUMORO suggestion
def move_cursor(table_text,cursor,row_destiny,col_destiny):
row=table_text.cellAt(cursor).row()
while not row==row_destiny:
if row<row_destiny:
cursor.movePosition(QTextCursor.NextRow)
else:
cursor.movePosition(QTextCursor.PreviousRow)
row=table_text.cellAt(cursor).row()
col=table_text.cellAt(cursor).column()
while not col==col_destiny:
if col<col_destiny:
cursor.movePosition(QTextCursor.NextCell)
else:
cursor.movePosition(QTextCursor.PreviousCell)
col=table_text.cellAt(cursor).column()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QTextEdit()
cursor=widget.textCursor()
table_text=cursor.insertTable(10,10)
# Format Table
fmt = table_text.format()
fmt.setWidth(QtGui.QTextLength(QtGui.QTextLength.PercentageLength, 100))
table_text.setFormat(fmt)
row=2
col=5
move_cursor(table_text,cursor,row,col)
cursor.insertText('Cell {} {}'.format(row,col))
#### RETMAS SUGGESTION
row=3
column=6
tableCell = table_text.cellAt(row, column)
cursor = tableCell.firstCursorPosition()
widget.setTextCursor(cursor)
cursor.insertText('Cell {} {}'.format(row,column))
widget.show()
sys.exit(app.exec_())
This works fine.

Related

Pyside6 shearing PDF file on window resize

I'm using QT (PySide) to view PDFs (using the PyMuPDF library) but when I resize I get a shearing artifact.
Like this:
Here is a minimal example:
import sys
import fitz
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QScrollArea
from PySide6.QtGui import QPixmap, QImage
from PySide6.QtCore import Qt
class PDFWindow(QMainWindow):
def __init__(self, filename):
super().__init__()
# Open the PDF and get the first page
self.pdf_doc = fitz.open(filename)
self.page = self.pdf_doc[0]
# Create a QLabel to hold the rendered page
self.label = QLabel()
self.label.setAlignment(Qt.AlignCenter)
# Create a QScrollArea to hold the label
self.scroll_area = QScrollArea()
self.scroll_area.setWidget(self.label)
self.scroll_area.setWidgetResizable(True)
self.setCentralWidget(self.scroll_area)
# Render the page and set it as the pixmap for the label
self.render_page()
# Connect the windowResized signal to the render_page function
self.resizeEvent = self.render_page
def render_page(self, event=None):
zoom = 1
if event is not None:
bound = self.page.bound()
page_width, page_height = bound.width, bound.height
zoom = min(event.size().width() / page_width,
event.size().height() / page_height)
pixmap = self.page.get_pixmap(matrix=fitz.Matrix(zoom, zoom),
colorspace='rgb')
image = QImage(pixmap.samples, pixmap.width, pixmap.height,
QImage.Format_RGB888)
cur_pixmap= QPixmap.fromImage(image)
self.label.setPixmap(cur_pixmap)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = PDFWindow("example.pdf")
window.show()
sys.exit(app.exec())

QTreeView item's editor position problem?

I have a QTreeView widget in which I have set indentation to 0 with QTreeView::setIndentation(0), but when editing an item, the editor still appears at the indentation level of the default indented behaviour:
I have tried changing the editor position with a QStyledItemDelegate::updateEditorGeometry's method, but it seems that there is a limit to where I can move the editor horizontally, as I cannot move it to a negative offset, past the x == 0 position, like for example QRect(-50, 0, 100, 30).
Any ideas would be greatly appreciated, thanks.
P.S.:
Here is an attempt of a minimal-reproducible-example, but this has another bug: the editor widget does not display when the geometry of the widget in drawRow is changed! The editor works when typing and pressing enter, it's just not displayed! I'll try to figure out what's the difference between my example in the image above and this code.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sip
class MyTreeWidget(QTreeWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setIndentation(0)
self.setMouseTracking(True)
self.setUniformRowHeights(True)
self.setExpandsOnDoubleClick(False)
self.setColumnCount(1)
self.setHeaderLabels(["Items"])
self.setHeaderHidden(True)
self.header().setVisible(False)
self.header().setStretchLastSection(False)
self.header().setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
self.add_items()
self.itemClicked.connect(self.click)
def click(self, item, column):
item.setFlags(
Qt.ItemFlag.ItemIsEditable |
Qt.ItemFlag.ItemIsEnabled |
Qt.ItemFlag.ItemIsSelectable
)
index = self.indexFromItem(item, 0)
self.edit(index)
def drawRow(self, painter, option, index):
model = self.model()
row = index.row()
column = index.column()
item = self.itemFromIndex(index)
widget = self.itemWidget(item, 0)
if widget is not None:
geo = QRect(widget.geometry())
geo.setX(geo.x() + 50)
widget.setGeometry(geo) # <- This line causes the editor's horizontal offset
super().drawRow(painter, option, index)
def add_items(self):
items = [
'Cookie dough',
'Hummus',
'Spaghetti',
'Dal makhani',
'Chocolate whipped cream'
]
parent = None
for item in items:
new_item = QTreeWidgetItem(None)
if parent is not None:
new_item = QTreeWidgetItem(parent)
else:
self.addTopLevelItem(new_item)
new_item.setText(0, item)
new_item.setExpanded(True)
parent = new_item
def edit_last_item(*args):
new_item.setFlags(
Qt.ItemFlag.ItemIsEditable |
Qt.ItemFlag.ItemIsEnabled |
Qt.ItemFlag.ItemIsSelectable
)
index = self.indexFromItem(new_item, 0)
self.edit(index)
print("Editing")
QTimer.singleShot(1000, edit_last_item)
class Window(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout(self)
self.setLayout(layout)
layout.addWidget(MyTreeWidget())
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
In trying to create a minimal reproducible example as #Parisa.H.R mentioned in the comment, I discovered that in the drawRow method in the QTreeView/QTreeWidget there is some code that adjusts the geometry of item widgets, like so (Python/PyQt example):
class MyTreeView(QTreeView):
def drawRow(self, painter, option, index):
model = self.model()
row = index.row()
column = index.column()
item = self.itemFromIndex(index)
widget = self.itemWidget(item, 0)
geo = ... # <- Code that calculates new geometry
widget.setGeometry(geo) # <- This line causes the editor's horizontal offset
super().drawRow(painter, option, index)
which is what causes the editor widget to be moved horizontally to the right.
Thanks #Parisa.H.R

QMovie setting filename second time wont work

I am setting the Initial Movie File like this:
self.movie = QMovie("dotGreenBlack.gif", QByteArray(), self)
At runtime, i want to change it by setting:
self.movie.setFileName("dotGreyStatic.gif")
But this leads to frame-freeze of the primarly set file "dotGreenBlack.gif"
Anything else i have to do to change the Gif-Animation on runtime?
Here is the fullcode:
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class ImagePlayer(QWidget):
def __init__(self, filename, title, parent=None):
QWidget.__init__(self, parent)
# Load the file into a QMovie
self.movie = QMovie(filename, QByteArray(), self)
size = self.movie.scaledSize()
self.setGeometry(200, 200, size.width(), size.height())
self.setWindowTitle(title)
self.movie_screen = QLabel()
# Make label fit the gif
self.movie_screen.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.movie_screen.setAlignment(Qt.AlignCenter)
# Create the layout
main_layout = QVBoxLayout()
main_layout.addWidget(self.movie_screen)
self.setLayout(main_layout)
# Add the QMovie object to the label
self.movie.setCacheMode(QMovie.CacheAll)
self.movie.setSpeed(100)
self.movie_screen.setMovie(self.movie)
self.movie.start()
self.movie.loopCount()
self.movie.setFileName("dotGreyStatic.gif")
self.movie_screen.setMovie(self.movie)
if __name__ == "__main__":
gif = "dotGreenBlack.gif"
app = QApplication(sys.argv)
app.setStyleSheet("QWidget { background-color: black }")
player = ImagePlayer(gif, "was")
player.show()
sys.exit(app.exec_())
Gif Icons used in this Example:
You just need to stop and restart the movie:
self.movie.stop()
self.movie.setFileName("dotGreyStatic.gif")
self.movie.start()

PySide crashing when replacing rows in QFormLayout

Using the following code example PySide segfaults when pushing "Add", "Add", "Remove", "Add" and due to some other sequences of interaction.
Python: 2.7.6
PySide: 1.2.1
QtCore: 4.8.5
Code:
from PySide.QtGui import *
from PySide.QtCore import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setObjectName('MainWindow')
self.baseLayout = QWidget(self)
self.v_layout = QVBoxLayout(self.baseLayout)
self.setCentralWidget(self.baseLayout)
self.form_layout = QFormLayout(self.baseLayout)
self.v_layout.addLayout(self.form_layout)
self.button_add = QPushButton(self.baseLayout)
self.button_add.setText("Add")
self.v_layout.addWidget(self.button_add)
self.button_del = QPushButton(self.baseLayout)
self.button_del.setText("Remove")
self.v_layout.addWidget(self.button_del)
self.button_add.clicked.connect(self.add)
self.button_del.clicked.connect(self.remove)
self.fields = []
def add_item(self):
layout = QHBoxLayout(self.parent())
line = QLineEdit(self.parent())
slider = QSlider(self.parent())
layout.addWidget(line)
layout.addWidget(slider)
self.fields.append((layout, line, slider))
self.form_layout.addRow("Test", layout)
def add(self):
for i in range(15):
self.add_item()
def remove(self):
for (layout, line, slider) in self.fields:
line.deleteLater()
slider.deleteLater()
while self.form_layout.itemAt(0):
child = self.form_layout.takeAt(0)
if child.widget():
child.widget().deleteLater()
self.form_layout.update()
self.fields = []
def main():
import sys
app = QApplication(sys.argv)
frame = MainWindow()
frame.show()
app.exec_()
if __name__ == '__main__':
main()
Is this the correct way of adding compound widgets (in this case a QLineEdit and a QSlider within a QVBoxLayout) to a form layout? What am I doing wrong?
The correct way of adding "compound widgets" to a QFormLayout is to create a QWidget that will be the parent to that layout.
add_item() should rather look something like this:
def add_item(self):
widget = QWidget(self.parent())
layout = QHBoxLayout(widget)
line = QLineEdit(widget)
slider = QSlider(widget)
layout.addWidget(line)
layout.addWidget(slider)
self.fields.append((layout, widget, line, slider))
self.form_layout.addRow("Test", widget)
(And the widget also has to be removed when deleting the fields).
I think you are not creating the layouts in the right way, for example you are trying to set the layout of base_layout two times. Also you can check for count() on a QLayout to see if it has children:
from PySide.QtGui import *
from PySide.QtCore import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.baseLayout = QWidget(self)
self.v_layout = QVBoxLayout(self.baseLayout)
self.setCentralWidget(self.baseLayout)
self.form_layout = QFormLayout()
self.v_layout.addLayout(self.form_layout)
self.button_add = QPushButton()
self.button_add.setText("Add")
self.v_layout.addWidget(self.button_add)
self.button_del = QPushButton()
self.button_del.setText("Remove")
self.v_layout.addWidget(self.button_del)
self.button_add.clicked.connect(self.add)
self.button_del.clicked.connect(self.remove)
self.fields = []
def add_item(self):
layout = QHBoxLayout()
line = QLineEdit()
slider = QSlider()
layout.addWidget(line)
layout.addWidget(slider)
self.fields.append((layout, line, slider))
self.form_layout.addRow("Test", layout)
def add(self):
for i in range(15):
self.add_item()
def remove(self):
while self.form_layout.count() > 0:
child = self.form_layout.takeAt(0)
widget = child.widget()
if widget:
widget.deleteLater()
self.form_layout.update()
self.fields = []
def main():
import sys
app = QApplication(sys.argv)
frame = MainWindow()
frame.show()
app.exec_()
if __name__ == '__main__':
main()

make the QMessageBox or QmainWindow in front of any overlapping sibling widgets?

If the active window belongs to some other process,how to make the QMessageBox or QmainWindow of this example in front of any overlapping sibling widgets when timeout ?
I tried raise_() and activateWindow() ,but both don’t work on WinXP
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.resize(800,600)
self.lcdNumber = QLCDNumber()
self.lcdNumber.setNumDigits(8)
layout = QVBoxLayout(self)
layout.addWidget(self.lcdNumber)
self.currentTime = QTime(0,0,0)
self.lcdNumber.display(self.currentTime.toString('hh:mm:ss'))
self.timer = QTimer(self)
self.timer.timeout.connect(self.updateLcdNumberContent)
self.timer.start(1000)
def updateLcdNumberContent(self):
self.currentTime = self.currentTime.addSecs(1)
self.lcdNumber.display(self.currentTime.toString('hh:mm:ss'))
if self.currentTime == QTime(0,0,4) :
msgBox = QMessageBox(self)
msgBox.setWindowTitle('iTimer')
msgBox.setIcon (QMessageBox.Information)
msgBox.setText("Time Out !!")
stopButton = msgBox.addButton("Stop", QMessageBox.ActionRole)
ignoreButton = msgBox.addButton(QMessageBox.Ignore)
stopButton.clicked.connect(self.timer.stop)
msgBox.show()
# self.raise_()
# self.activateWindow()
if __name__ == '__main__':
app =QApplication(sys.argv)
frame = MainWindow()
frame.show()
sys.exit(app.exec_())
Try to modify window flags by using QWidget::setWindowFlags() method of your QMessageBox or QMainWindow. You should use Qt::WindowStaysOnTopHint flag for your purpose.
It will be something like window->setWindowFlags(window->windowFlags() | Qt::WindowStaysOnTopHint).
If you will not succeed with just setWindowFlags(window->windowFlags() | Qt::WindowStaysOnTopHint), you will need to use Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint with another flags. Experiment with it and you'll succeed.

Resources