Paste in the field of QTableView - python

I need to implement a function in python which handles the "paste" when "ctrl+v" is pressed. I have a QTableView, i need to copy a field of the table and paste it to another field of the table. I have tried the following code, but the problem is that i don't know how to read the copied item (from the clipboard) in the tableView. (As it already copies the field and i can paste it anywhere else like a notepad). Here is part of the code which I have tried:
class Widget(QWidget):
def __init__(self,md,parent=None):
QWidget.__init__(self,parent)
# initially construct the visible table
self.tv=QTableView()
self.tv.show()
# set the shortcut ctrl+v for paste
QShortcut(QKeySequence('Ctrl+v'),self).activated.connect(self._handlePaste)
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.tv)
# paste the value
def _handlePaste(self):
if self.tv.copiedItem.isEmpty():
return
stream = QDataStream(self.tv.copiedItem, QIODevice.ReadOnly)
self.tv.readItemFromStream(stream, self.pasteOffset)

You can obtain the clipboard form the QApplication instance of your app using QApplication.clipboard(), and from the QClipboard object returned you can get the text, image, mime data, etc. Here is an example:
import PyQt4.QtGui as gui
class Widget(gui.QWidget):
def __init__(self,parent=None):
gui.QWidget.__init__(self,parent)
# initially construct the visible table
self.tv=gui.QTableWidget()
self.tv.setRowCount(1)
self.tv.setColumnCount(1)
self.tv.show()
# set the shortcut ctrl+v for paste
gui.QShortcut(gui.QKeySequence('Ctrl+v'),self).activated.connect(self._handlePaste)
self.layout = gui.QVBoxLayout(self)
self.layout.addWidget(self.tv)
# paste the value
def _handlePaste(self):
clipboard_text = gui.QApplication.instance().clipboard().text()
item = gui.QTableWidgetItem()
item.setText(clipboard_text)
self.tv.setItem(0, 0, item)
print clipboard_text
app = gui.QApplication([])
w = Widget()
w.show()
app.exec_()
Note: I've used a QTableWidget cause I don't have a model to use with QTableView but you can adapt the example to your needs.

Related

PySide6 Exclude Folders from QTreeView

I have an application where i need to display 2 different TreeViews. One for showing the folders (folderView) and the other will display the Files (fileView) inside the selected folder from the folderView. The following Code works fine but i am having a strange issue:
in the screen shot below, if i click on the bin folder for example, then switch back to VBoxGuestAdd.., the fileView will display the bin folder in the fileView.
p.s.: using an ubuntu 22.04 machine
and here my code:
import sys
from PySide6.QtCore import QDir
from PySide6.QtWidgets import QApplication, QWidget, QHBoxLayout, QTreeView, QFileSystemModel
def folderView_selectionchanged():
current_index = folderView.currentIndex()
selected_folder_path = folderModel.fileInfo(current_index).absoluteFilePath()
fileView.setRootIndex(fileModel.setRootPath(selected_folder_path))
app = QApplication(sys.argv)
window = QWidget()
layout = QHBoxLayout()
folderView = QTreeView()
folderModel = QFileSystemModel()
folderModel.setRootPath("/")
folderModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
folderView.setModel(folderModel)
folderView.selectionModel().selectionChanged.connect(folderView_selectionchanged)
fileView = QTreeView()
fileModel = QFileSystemModel()
fileModel.setRootPath("/")
fileModel.setFilter(QDir.NoDotAndDotDot | QDir.Files)
fileView.setModel(fileModel)
layout.addWidget(folderView)
layout.addWidget(fileView)
window.setLayout(layout)
window.show()
app.exec()
This is a "bug" probably caused by the asynchronous nature of QFileSystemModel, which uses threading to fill the model and delays calls for the model structure updates.
It seems that it's also been already reported as QTBUG-93634, but it has got no attention yet.
A possible workaround is to "reset" the filter and set it again:
def folderView_selectionchanged():
current_index = folderView.currentIndex()
selected_folder_path = folderModel.fileInfo(current_index).absoluteFilePath()
fileView.setRootIndex(fileModel.setRootPath(selected_folder_path))
fileModel.setFilter(QDir.AllDirs)
fileModel.setFilter(QDir.NoDotAndDotDot | QDir.Files)
But the above might not work for big/slow file systems. The only possible solution I can think of is to use a QSortFilterProxyModel and override the filterAcceptsRow() function. It will not be as fast as the basic model, but it will work as expected.
Note that:
filterAcceptsRow() is always checked against the model hierarchy, so always allowing the filter to pass anything outside the filtered directory is mandatory, otherwise it will be filtered out (if the parent directory is filtered out, there is no child to show);
since setRootPath() invalidates the layout and checks the filters again, we must clear the validation until the new root path is set, and then restore it and reset the filters again; this is done by temporarily replacing the actual filtering function with a dummy one that always returns True;
class FileProxy(QSortFilterProxyModel):
validParent = None
def __init__(self):
super().__init__()
self.fsModel = QFileSystemModel()
self.setSourceModel(self.fsModel)
def filterAcceptsRow(self, row, parent):
return (
self.validParent != parent
or not self.fsModel.isDir(
self.fsModel.index(row, 0, parent))
)
def setRootPath(self, path):
func = self.filterAcceptsRow
self.filterAcceptsRow = lambda *args: True
self.validParent = self.fsModel.setRootPath(path)
self.filterAcceptsRow = func
self.invalidateFilter()
return self.mapFromSource(self.validParent)

Python PyQt6 QTableView first time selecting item with mouse in table, "selectedIndexes()" returns empty list

I am having an issue that I haven't been able to figure out. When my table loads, selecting any first item and attempting to return it's index via selectedIndexes(), the index is empty. If I then click anywhere else, the method works as intended. Why? Here's some MRC:
from PyQt6.QtCore import pyqtSignal, Qt
from PyQt6.QtGui import QStandardItem, QStandardItemModel
from PyQt6 import QtWidgets as qt
import sys
class Main(qt.QMainWindow):
def __init__(self):
super().__init__()
frame = qt.QFrame()
self.setCentralWidget(frame)
laymb = qt.QVBoxLayout(frame)
model = QStandardItemModel()
tabmb = TableViewClick()
tabmb.setModel(model)
tabmb.setGridStyle(Qt.PenStyle(0))
tabmb.setSelectionMode(qt.QTableView.SelectionMode(1))
tabmb.setSelectionBehavior(tabmb.SelectionBehavior(1))
laymb.addWidget(tabmb)
subj = []
for e in range(10):
subj.append(QStandardItem('Testing...'))
model.appendColumn(subj)
tabmb.signal.connect(self._click_table)
def _click_table(self):
table = self.sender()
indexes = table.selectedIndexes()
print(indexes)
class TableViewClick(qt.QTableView):
signal = pyqtSignal()
def mousePressEvent(self, event):
self.signal.emit()
qt.QTableView.mousePressEvent(self, event)
app = qt.QApplication(sys.argv)
main_gui = Main()
main_gui.show()
sys.exit(app.exec())
As you can see, I've tied it to a mousePressEvent because I need to call _click_table for later code. I've troubleshot some and can select a row via selectRow(), and the above does not happen, but I don't want to do that because the GUI loads with a row already selected. Any ideas how you can get the first time you click anywhere in the table to return the index? With the index I'm going to get the row clicked for later code. If there's a better way, I'm open to it. But, I want to click an item and get the row.

QTreeWidget dropped item gets deleted when using setDropAction

I am trying to make a QTreeWidget that lets the user rearrange its elements, and if the user drags and drops a tree item to another widget I don't want the item to be deleted. To get this behavior, I'm trying to use setDropAction in dropEvent.
The code below successfully rejects drops from other widgets, and allows drops to other widgets without deleting the original, but it seems to break drag-and-drop within the tree - it causes the item to disappear when dropped.
https://www.screencast.com/t/driIjyg8ekzt
import sys
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtCore import Qt
class MyTree(QtWidgets.QTreeWidget):
def __init__(self):
super().__init__()
self.setDragDropMode(self.DragDrop)
self.setSelectionMode(self.ExtendedSelection)
self.setSelectionBehavior(self.SelectRows)
self.setDefaultDropAction(Qt.CopyAction)
self.setAcceptDrops(True)
def dropEvent(self, e: QtGui.QDropEvent):
if e.source() is self:
print("move")
e.setDropAction(Qt.MoveAction)
e.accept()
super().dropEvent(e)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
my_list = QtWidgets.QListWidget()
my_list.addItems(list('1234'))
my_list.show()
my_list.setDragEnabled(True)
my_list.setAcceptDrops(True)
my_tree = MyTree()
for item in list('abcd'):
QtWidgets.QTreeWidgetItem(my_tree, [item])
my_tree.show()
sys.exit(app.exec_())
If you just want to prevent drop from external sources, just use:
self.setDragDropMode(self.InternalMove)
And don't reimplement dropEvent().
Your code doesn't work properly mostly because you've set the event as accepted, and an item view ignores a drop event if it has already been accepted.
In your case, it would be better to do this:
def dzropEvent(self, e: QtGui.QDropEvent):
if e.source() != self:
# ignore the drop from other sources
return
e.setDropAction(Qt.MoveAction)
super().dropEvent(e)
But if you really want to ignore external drops, you should ignore the event right from the dragEnterEvent(), so that it's made also clear to the user that dropping is not allowed.

Store string variables from PyQt4 Text Box

I have created a small uic file with qt Designer in order to build a small gui using PyQt4. One of the elements of that gui is a simple textbox, where I set a string value (textbox is called RiskDate_Box). After setting this value in the GUI, I want to use it as a string variable in the following code (not seen here) . My problem is, that I am not able to store it, in the code seen below I tried it in two different ways ( store it as Riskdate1 and Riskdate2). After compiling the code, bothvariables are empty and not equal to the value I set in the GUI, e.g. '12.08.2012'. However, if I compile the script and after that only compile
Riskdate2=window.RiskDate_Box.toPlainText()
then the Riskdate set in the Gui is correctly assigned to the variable 'Riskdate2' as a string. Would be great if someone could help me with that issue.
from PyQt4 import QtCore, QtGui, uic
import sys
# Gui Code
qtCreatorFile = "untitled.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyWindow(QtGui.QDialog):
def __init__(self):
super(MyWindow, self).__init__()
uic.loadUi("untitled.ui", self)
self.show()
self.RiskDate=self.RiskDate_Box.toPlainText()
if __name__ == '__main__':
app=QtGui.QApplication.instance()
app=0
app = QtGui.QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
window = MyWindow()
#Try 1 to store variable
Riskdate1=window.RiskDate
# Try 2 to store variable
Riskdate2=window.RiskDate_Box.toPlainText()
sys.exit(app.exec_())
you need to send s signal when text in your QPlainTextEdit is changed
void QPlainTextEdit::textChanged()
This signal is emitted whenever the document's content changes; for example, when text is inserted or deleted, or when formatting is applied.
you need to do something like:
self.RiskDate_Box.textChanged.connect(self.get_text)
self.show()
def get_text(self):
self.RiskDate = self.RiskDate_Box.toPlainText())
print (self.RiskDate)

How to embed URL link to QLabel

Clicking QLabel should open a default web browser with URL link specified. It is not happening yet. Why?
A second question. Would it be possible to override the default blue color of the Label's font with something else?
class Widget(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
vLayout=QtGui.QVBoxLayout(self)
self.setLayout(vLayout)
urlLink="'Click this link to go to Google'"
label=QtGui.QLabel(self)
label.setText(urlLink)
vLayout.addWidget(label)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
The styling of the label's contents can be modified using the standard html syntax.
To automatically open external links:
label.setOpenExternalLinks(True)
In Qt Designer,
Ensure the label object containing the link is selected,
Locate the openExternalLinks property within the QLabel Group in the Property Editor (you can type open into the Property Editor filter field),
Set property openExternalLinks to True (checked). [This property is set to False by default.]

Categories

Resources