I have written small program and would like to use underline format rather than selected text which is provided by QplainTextEdit
it work well, when i click mouse left click
But when i Use shift+left click, qplaintextedit select complete text and underline format gone.
I am trying to use only underline format and do not select text.
Expected behavior for shift+left click
#!/usr/bin/python3.6
from PySide2.QtCore import Qt, QEvent
from PySide2.QtWidgets import QApplication
from PySide2.QtGui import (QTextCharFormat, QIcon, QKeySequence,
QBrush, QColor, QTextDocument, QFont,
QTextCursor, QTextBlockFormat, QFontDatabase)
from PySide2.QtWidgets import (QPlainTextEdit, QSizePolicy, QApplication, QLabel, QGridLayout, QMessageBox, QToolBar, QTextEdit, QCheckBox, QAction,
QTableWidget, QTableWidgetItem, QHeaderView, QMenu,
QWidget)
from PySide2.QtCore import Qt, QSize, QRegExp, QFile, QTextStream, QRect
from PySide2.QtWidgets import (QMainWindow, QVBoxLayout,
QPlainTextEdit, QGridLayout, QGroupBox,
QListWidget, QHBoxLayout, QLabel, QLineEdit,
QMenuBar, QPushButton, QMessageBox, QDialog,
QTextEdit, QVBoxLayout, QWidget, QFormLayout,
QCheckBox, QDialogButtonBox,
QTableWidget, QTableWidgetItem, QHeaderView)
import sys
class Window(QMainWindow):
def __init__(self, app):
super().__init__()
self.shift_left_click_cursor = []
def create_widget(self):
self.plain_textedit = QPlainTextEdit()
self.plain_textedit.setLineWrapMode(QPlainTextEdit.NoWrap)
self.plain_textedit.setStyleSheet(
"""QPlainTextEdit {font-size: 14pt;
font-family: Courier;}""")
self.plain_textedit.setMouseTracking(True)
self.plain_textedit_format = self.plain_textedit.currentCharFormat()
self.plain_textedit.setCursorWidth(5)
self.plain_textedit.viewport().installEventFilter(self)
main_layout = QVBoxLayout()
main_layout.addWidget(self.plain_textedit)
self.window = QWidget()
self.window.setLayout(main_layout)
self.setCentralWidget(self.window)
def eventFilter(self, obj, event):
if obj is self.plain_textedit.viewport() and event.type() == QEvent.MouseButtonPress:
#Reseting format for single click when user use shift+click select data
if event.button() == Qt.LeftButton:
text_cursor = self.plain_textedit.cursorForPosition(event.pos())
text_cursor.select(QTextCursor.LineUnderCursor)
format = QTextCharFormat()
format.setForeground(QBrush(QColor("blue")))
format.setUnderlineStyle(QTextCharFormat.SingleUnderline)
text_cursor.mergeCharFormat(format)
modifiers = QApplication.keyboardModifiers()
if modifiers == Qt.ShiftModifier:
self.shift_left_click_cursor.append(text_cursor)
self.change_summary_block_format()
def change_summary_block_format(self):
start_line = self.shift_left_click_cursor[0].blockNumber()
end_line = self.shift_left_click_cursor[-1].blockNumber()
index = 0
plain_textcursor = self.plain_textedit.textCursor()
plain_textcursor.select(QTextCursor.Document)
plain_textcursor.setCharFormat(self.plain_textedit_format)
plain_textcursor.clearSelection()
for line in range(start_line, end_line + 1):
text_data = self.plain_textedit.document().findBlockByLineNumber(line)
print(text_data.text())
text_cursor = QTextCursor(text_data)
# self.plaintext_cursor_multiselection(text_data)
print(text_data)
def main():
app = QApplication([])
window = Window(app)
window.create_widget()
window.show()
app.exec_()
if __name__ == "__main__":
sys.exit(main())
If you send the event to the QPlainTextEdit then you can get the position and anchor of the selection and move them to cover the whole line.
class Window(QMainWindow):
def __init__(self, app):
super().__init__()
self.shift_left_click_cursor = []
def create_widget(self):
self.plain_textedit = QPlainTextEdit()
self.plain_textedit.setLineWrapMode(QPlainTextEdit.NoWrap)
self.plain_textedit.setStyleSheet(
"""QPlainTextEdit {font-size: 14pt;
font-family: Courier;}""")
self.plain_textedit.setMouseTracking(True)
self.plain_textedit_format = self.plain_textedit.currentCharFormat()
self.plain_textedit.setCursorWidth(5)
self.plain_textedit.viewport().installEventFilter(self)
main_layout = QVBoxLayout()
main_layout.addWidget(self.plain_textedit)
self.window = QWidget()
self.window.setLayout(main_layout)
self.setCentralWidget(self.window)
def eventFilter(self, obj, event):
if obj is self.plain_textedit.viewport() and event.type() == QEvent.MouseButtonPress:
#Reseting format for single click when user use shift+click select data
if event.button() == Qt.LeftButton and event.modifiers() & Qt.ShiftModifier:
self.plain_textedit.mousePressEvent(event)
text_cursor = self.plain_textedit.textCursor()
positions = (text_cursor.anchor(), text_cursor.position())
text_cursor.setPosition(min(positions))
text_cursor.movePosition(QTextCursor.StartOfLine)
text_cursor.setPosition(max(positions), QTextCursor.KeepAnchor)
text_cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
format = QTextCharFormat()
format.setForeground(QBrush(QColor("blue")))
format.setUnderlineStyle(QTextCharFormat.SingleUnderline)
text_cursor.mergeCharFormat(format)
text_cursor.clearSelection()
text_cursor.setPosition(positions[1])
self.plain_textedit.setTextCursor(text_cursor)
return True
return super().eventFilter(obj, event)
Note that you could instead subclass QPlainTextEdit and reimplement mousePressEvent.
class PlainTextEdit(QPlainTextEdit):
def mousePressEvent(self, event):
super().mousePressEvent(event)
if event.button() == Qt.LeftButton and event.modifiers() & Qt.ShiftModifier:
text_cursor = self.textCursor()
positions = (text_cursor.anchor(), text_cursor.position())
text_cursor.setPosition(min(positions))
text_cursor.movePosition(QTextCursor.StartOfLine)
text_cursor.setPosition(max(positions), QTextCursor.KeepAnchor)
text_cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
format = QTextCharFormat()
format.setForeground(QBrush(QColor("blue")))
format.setUnderlineStyle(QTextCharFormat.SingleUnderline)
text_cursor.mergeCharFormat(format)
text_cursor.clearSelection()
text_cursor.setPosition(positions[1])
self.setTextCursor(text_cursor)
Related
If you enter an age less than 18 or more than 80 and click on the button, a modal window will light up, but the button will be in the pressing mode and will turn dark, the same with RadioButton will only be highlighted in blue, is it possible to remove it somehow? When you click on another field, everything is fine
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt,QEvent, Signal)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform, QFocusEvent)
from PySide6.QtWidgets import (QApplication, QGridLayout, QHBoxLayout, QLabel,
QLineEdit, QMainWindow, QSizePolicy, QWidget, QRadioButton, QPushButton, QVBoxLayout, QMessageBox)
class QTApp(QWidget):
def __init__(self):
super(QTApp, self).__init__()
self.LE_sample_input_01 = QLineEdit()
self.LE_sample_input_02 = QLineEdit()
self.LE_sample_input_01.setPlaceholderText('Age')
self.RadioButton = QRadioButton('Something')
self.Button = QPushButton('Click')
self.Button.setStyleSheet("QPushButton:pressed {background-color: #b3b3ba;}")
layout = QVBoxLayout(self)
layout.addWidget(self.LE_sample_input_01)
layout.addWidget(self.LE_sample_input_02)
layout.addWidget(self.RadioButton)
layout.addWidget(self.Button)
self.LE_sample_input_01.installEventFilter(self)
def eventFilter(self, obj, event):
if event.type() == QEvent.FocusOut and QFocusEvent.reason(event) == Qt.MouseFocusReason:
if obj is self.LE_sample_input_01:
try:
age = int(self.LE_sample_input_01.text())
if age < 18 or age > 80:
error = QMessageBox()
error.setWindowTitle('Age error')
error.setText('Age entered incorrectly (from 18 to 80 years)')
error.setIcon(QMessageBox.Warning)
error.addButton('Ok',QMessageBox.AcceptRole)
error.exec()
obj.setFocus()
obj.selectAll()
return True
except: pass
return False
if __name__ == "__main__":
app = QApplication()
qt_app = QTApp()
qt_app.show()
app.exec()
I have a problem with my python code, it's a QTablewidget with Qpushbuttons and Qline_edits inside each cell, We want a file path (after selecting this file from the file browser) to be written in the line edit when we click on its pushbutton and to store the output files so we can use them after.
from PyQt5.QtWidgets import (
QMainWindow,
QApplication,
QPushButton,
QFileDialog,
QGridLayout,
QLineEdit,
QTableWidget,
QHBoxLayout,
QWidget,
)
from PyQt5.QtCore import pyqtSlot
import sys
from functools import partial
global list_C
list_C=[]
class boxlayout(QWidget):
def __init__(self):
super(boxlayout,self).__init__()
layout=QHBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
boxlayout.le=QLineEdit()
boxlayout.btn=QPushButton()
layout.addWidget(boxlayout.le)
layout.addWidget(boxlayout.btn)
self.setLayout(layout)
class Main(QMainWindow):
def __init__(self):
super().__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
mainlayout = QGridLayout(centralWidget)
self.table = QTableWidget(self)
self.table.resize(640, 480)
self.table.setColumnCount(3)
self.table.setRowCount(4)
mainlayout.addWidget(self.table)
save_button=QPushButton('OK')
mainlayout.addWidget(save_button)
save_button.clicked.connect(self.save_as_list)
for i in range(4):
for j in range(3):
self.table.setCellWidget(i,j, boxlayout())
boxlayout.btn.clicked.connect(partial(self.open_dialog, boxlayout.le))
#pyqtSlot(QLineEdit)
def open_dialog(self, le: QLineEdit):
file_name = QFileDialog.getOpenFileName(
self,
"Open File",
"${HOME}",
"All Files (*)",
)
le.setText(file_name[0])
def save_as_list(self):
for i in range(4):
for j in range(3):
item=self.table.cellWidget(i,j).le.text()
list_C.append(item)
print(list_C) #output=['last le value','last le value',...]
if __name__ == "__main__":
app = QApplication(sys.argv)
main_gui = Main()
main_gui.show()
sys.exit(app.exec())
Here is a minimal example:
from PyQt5.QtWidgets import (
QMainWindow,
QApplication,
QPushButton,
QFileDialog,
QFrame,
QGridLayout,
QLineEdit,
)
from PyQt5.QtCore import pyqtSlot
import sys
from functools import partial
class Main(QMainWindow):
def __init__(self):
super().__init__()
top_frame = QFrame(self)
self.setCentralWidget(top_frame)
self.grid = QGridLayout(top_frame)
for i in range(10):
btn = QPushButton(top_frame)
le = QLineEdit(top_frame)
btn.clicked.connect(partial(self.open_dialog, le))
btn.setText("open file system dialog")
self.grid.addWidget(btn, i, 0)
self.grid.addWidget(le, i, 1)
#pyqtSlot(QLineEdit)
def open_dialog(self, le: QLineEdit):
file_name = QFileDialog.getOpenFileName(
self,
"Open File",
"${HOME}",
"All Files (*)",
)
le.setText(file_name[0])
if __name__ == "__main__":
app = QApplication(sys.argv)
main_gui = Main()
main_gui.show()
sys.exit(app.exec())
The key thing here is to pass the QLineEdit to the file selector method.
Here we are doing it with: lambda: self.open_dialog(le)
There are lots of tutorials out there that show you how to create userforms in Python, but I can't find any which then show you how to retrieve whatever is entered into that form.
Here's an example I found where the userform looks perfect, but the buttons don't do anything:
from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout)
import sys
class Dialog(QDialog):
NumGridRows = 3
NumButtons = 4
def __init__(self):
super(Dialog, self).__init__()
self.createFormGroupBox()
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttonBox.accepted.connect(self.accept)
# buttonBox.accepted.connect(self.getInfo)
buttonBox.rejected.connect(self.reject)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(buttonBox)
self.setLayout(mainLayout)
self.setWindowTitle("Form Layout - pythonspot.com")
# def getInfo(self):
# shost = self.Name.text()
# print(shost)
def createFormGroupBox(self):
self.formGroupBox = QGroupBox("Form layout")
layout = QFormLayout()
layout.addRow(QLabel("Name"), QLineEdit())
layout.addRow(QLabel("Country"), QComboBox())
layout.addRow(QLabel("Age"), QSpinBox())
self.formGroupBox.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = Dialog()
sys.exit(dialog.exec_())
The commented lines are lines that I added that don't work. Obviously self.Name.text() isn't the right syntax, but I can't figure out what is.
There are lot of things that you are missing in the code.
e.g buttonBox.accepted.connect(self.accept) accept button is connected to dummy accept. you need to connect this button to your self.getInfo,
To answer why you are failing to retrieve values: you do not have object handles from your QLineEdit, QComboBox, QSpinBox which means you cannot access them later to read the updated text.
Following is the fixed code which will connect accept to self.getInfo(self) and upon pressing OK it will print the values in Name, Country, Age fields .
from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout)
import sys
class Dialog(QDialog):
NumGridRows = 3
NumButtons = 4
def __init__(self):
super(Dialog, self).__init__()
self.formGroupBox = QGroupBox("Form layout")
self.ageSpinBar = QSpinBox()
self.countryComboBox = QComboBox()
self.countryComboBox.addItems(["Pakistan", "USA", "UAE"])
self.nameLineEdit = QLineEdit()
self.createFormGroupBox()
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self.getInfo)
# buttonBox.accepted.connect(self.getInfo)
self.buttonBox.rejected.connect(self.reject)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.buttonBox)
self.setLayout(mainLayout)
self.setWindowTitle("Form Layout - pythonspot.com")
def getInfo(self):
print("Person Name : {0}".format(self.nameLineEdit.text()))
print("Country : {0}".format(self.countryComboBox.currentText()))
print("Age : {0}".format(self.ageSpinBar.text()))
self.close()
def createFormGroupBox(self):
layout = QFormLayout()
layout.addRow(QLabel("Name"), self.nameLineEdit)
layout.addRow( QLabel("Country"),self.countryComboBox)
layout.addRow( QLabel("Age"), self.ageSpinBar)
self.formGroupBox.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = Dialog()
sys.exit(dialog.exec_())
Note : self.close() will close the window if you don't want to close just comment this line out.
Hope this helps :)
I need it to be not continuously printing but instead it only change the QLabel,
I dont need to add more, just whenever you write in Line edit it should replace the existing text. I need it like a stocks
This is the code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QLabel, QLineEdit
from PyQt5.QtCore import pyqtSlot
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.hbox = QHBoxLayout()
self.game_name = QLabel("Stocks:", self)
self.game_line_edit = QLineEdit(self)
self.search_button = QPushButton("Print", self)
self.search_button.clicked.connect(self.on_click)
self.hbox.addWidget(self.game_name)
self.hbox.addWidget(self.game_line_edit)
self.hbox.addWidget(self.search_button)
self.setLayout(self.hbox)
self.show()
#pyqtSlot()
def on_click(self):
game = QLabel(self.game_line_edit.text(), self)
self.hbox.addWidget(game)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
You have to create a QLabel, set it in the layout and only update the text with setText():
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QLabel, QLineEdit
from PyQt5.QtCore import pyqtSlot
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.game_name = QLabel("Stocks:")
self.game_line_edit = QLineEdit()
self.search_button = QPushButton("Print")
self.search_button.clicked.connect(self.on_click)
self.game = QLabel()
hbox = QHBoxLayout(self)
hbox.addWidget(self.game_name)
hbox.addWidget(self.game_line_edit)
hbox.addWidget(self.search_button)
hbox.addWidget(self.game)
self.show()
#pyqtSlot()
def on_click(self):
self.game.setText(self.game_line_edit.text())
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
I put a QLineEdit in form.ui, and I want to use CustomLabel to inheriance it. But there are both 2 QLineEdit(lines in form.ui and CustomLabel) in my mainwindow.
How should I deal with this situation?
Here is the image of my programme
Here is my code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit, QLabel
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
import PyQt5.uic as uic
form_ui,_ =uic.loadUiType('form.ui')
print(type(form_ui))
class Mainwindow(QWidget,form_ui):
"""docstring for App"""
def __init__(self):
super(Mainwindow, self).__init__()
self.setupUi(self)
path_lineEdit = CustomLabel(self.lines)
class CustomLabel(QLineEdit):
def __init__(self,parent=None):
super(CustomLabel,self).__init__(parent)
# self.resize(parent.size())
def dragEnterEvent(self, e):
if e.mimeData().hasFormat('text/plain'):
e.accept()
else:
e.ignore()
def dropEvent(self, e):
self.setText('212'+e.mimeData().text())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Mainwindow()
ex.show()
sys.exit(app.exec_())