Morning/Afternoon/Evening
I've hit a brick wall previously I was able to have a QLineEdit be able to give you autofill options such as:
Autofill (Can't embedded images so its a link)
Previously the values were sorted in a list and using QCompleter and QStringListModel this was possible.
Having moved my form that was all QLineEdits to now just a QTableWidget. I want to achieve the same effect as previous with QLineEdit where if you type in the field labaled "Fittings" it will preform as previous. The values that were before stored in a List are now in a SQL DB.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
import tkinter
import sqlite3
import sys
connection = sqlite3.connect("PriceList.db")
# Getting Screen info
root = tkinter.Tk()
root.withdraw()
def setup(uname):
global user
user = uname
# Layout
layout = QHBoxLayout()
right_side = QGridLayout()
right_side.setAlignment(Qt.AlignTop)
left_side = QVBoxLayout()
class QuotesWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(QuotesWindow, self).__init__(*args, **kwargs)
# Window Settings
self.setWindowTitle("Herpy - " + user)
self.setWindowIcon(QIcon("icon.png"))
self.showMaximized()
# Right Side Enter Quote
self.input_table()
right_side.addWidget(self.tableWidget)
# Mid Line
mid_line = QFrame()
mid_line.setFrameShape(QFrame.VLine)
mid_line.setFrameShadow(QFrame.Sunken)
# Left Side Details
acc_bt = QPushButton("Account")
left_side.addWidget(acc_bt)
# Who
who_box = QLineEdit()
who_box.setPlaceholderText("Name")
left_side.addWidget(who_box)
# Street
street_box = QLineEdit()
street_box.setPlaceholderText("Street")
left_side.addWidget(street_box)
# Town
town_box = QLineEdit()
town_box.setPlaceholderText("Town")
left_side.addWidget(town_box)
# County
county_box = QLineEdit()
county_box.setPlaceholderText("County")
left_side.addWidget(county_box)
# Postcode
postc_box = QLineEdit()
postc_box.setPlaceholderText("Postcode")
left_side.addWidget(postc_box)
# Telephone
telep_box = QLineEdit()
telep_box.setPlaceholderText("Telephone Number")
left_side.addWidget(telep_box)
# Seperator
left_line = QFrame()
left_line.setFrameShape(QFrame.HLine)
left_line.setFrameShadow(QFrame.Sunken)
left_side.addWidget(left_line)
# Author
q_author = QLineEdit()
q_author.setPlaceholderText(user)
q_author.setReadOnly(True)
left_side.addWidget(q_author)
# Placed By
placed_b = QLineEdit()
placed_b.setPlaceholderText("Placed By")
left_side.addWidget(placed_b)
# Placed With
placed_w = QLineEdit()
placed_w.setPlaceholderText("Placed With")
left_side.addWidget(placed_w)
# Reference
ref_input = QLineEdit()
ref_input.setPlaceholderText("Reference")
left_side.addWidget(ref_input)
# To Fill Space
left_side.addStretch(1)
# Layouts
layout.addLayout(left_side)
layout.addWidget(mid_line)
layout.addLayout(right_side)
# Shortcut
shortcut = QShortcut(QKeySequence("Shift+Return"), self)
#shortcut.activated.connect(self.new_input)
# Makes it fucking render
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.show()
def input_table(self):
# Auto Fill for Fittings
model = QSqlTableModel()
model.select()
completer = QCompleter()
completer.setCompletionColumn(1)
#completer.setCaseSensitivity(CaseInsensitive)
#completer.setCompletionRole(QtCore.Qt.EditRole)
#Create table
headers = ["Fittings", "Quantity", "Price", "Total"]
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(50)
self.tableWidget.setColumnCount(4)
self.tableWidget.setItem(0,0, QTableWidgetItem("Cell (1,1)"))
self.tableWidget.move(0,0)
self.tableWidget.setColumnWidth(1, 80)
self.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
#self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
#self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget.setHorizontalHeaderLabels(headers)
Thanks in advance :) Sorry its a bit messy
Edit: Was marked a dupe and give sqlite3 table into QTableWidget, sqlite3, PyQt5
Can't see how it corresponds with my code, am I missing something?
Edit2: Changed text so its more understable
Related
In PyQt, I have a basic program. It consists of 2 combo boxes, 1 line edit and 3 checkboxes. What I want to do is, depending on the item of the first combo box, hide / show specific widgets. However, I keep getting an error: 'ExportDialog' object has no attribute 'exportSetDelimiter_lbl'. I have defined this widget above in initUI, and I run initUIininit`, so I'm not sure why I am getting this error. Here is my code:
from PyQt5 import QtGui, QtCore, QtWidgets
import sys
class ExportDialog(QtWidgets.QMainWindow):
def __init__(self,imagePath):
super(ExportDialog, self).__init__()
self.initUI(imagePath)
#Set The GUI Position And Size
self.setGeometry(500, 500, 600, 450)
#Set The GUI Title
self.setWindowTitle("Export Deck")
#Set The GUI Icon
self.setWindowIcon(QtGui.QIcon('MainFlashcardAppIcon.png'))
def initUI(self, PATH):
#Create The New Deck Label
self.exportFormat_lbl = QtWidgets.QLabel(self)
self.exportFormat_lbl.setText("Export Format: ")
exportFormat_font = QtGui.QFont()
exportFormat_font.setPointSize(8)
self.exportFormat_lbl.setFont(exportFormat_font)
self.exportFormat_lbl.adjustSize()
self.exportFormat_combo = QtWidgets.QComboBox()
self.exportFormat_combo.setMinimumHeight(35)
self.exportFormat_combo.setFixedWidth(380)
self.exportFormat_combo.currentTextChanged.connect(self.on_combobox_changed)
self.exportDeckName_lbl = QtWidgets.QLabel(self)
self.exportDeckName_lbl.setText("Include: ")
self.exportDeckName_lbl.setFont(exportFormat_font)
self.exportDeckName_lbl.adjustSize()
self.exportDeckName_combo = QtWidgets.QComboBox()
self.exportDeckName_combo.setMinimumHeight(35)
self.exportDeckName_combo.setFixedWidth(380)
self.exportFormat_combo.addItem(".TXT")
self.exportFormat_combo.addItem(".CSV")
self.exportFormat_combo.addItem(".DB")
self.exportSetDelimiter_lbl = QtWidgets.QLabel()
self.exportSetDelimiter_lbl.setText("Set Delimiter (Leave blank for standard delimited):")
self.exportSetDelimiter_txt = QtWidgets.QLineEdit()
self.exportSetDelimiter_txt.setMaxLength(1)
self.exportSetDelimiter = QtWidgets.QLineEdit()
vboxExport_setDelimiter = QtWidgets.QVBoxLayout()
vboxExport_setDelimiter.addWidget(self.exportSetDelimiter_lbl)
vboxExport_setDelimiter.addWidget(self.exportSetDelimiter_txt)
self.includeMedia_check = QtWidgets.QCheckBox("Include HTML and Media References")
self.includeTags_check = QtWidgets.QCheckBox("Include Tags")
self.includeAllSQL_check = QtWidgets.QCheckBox("Include All SQL Tables")
self.exportFormat_combo.addItem("B3 Biology")
self.exportFormat_combo.addItem("B2 Biology")
self.exportFormat_combo.addItem("B1 Biology")
self.allComboList = ["B3 Biology", "B2 Biology", "B1 Biology"]
self.exportDeckName_combo.setCurrentIndex(self.allComboList.index(PATH))
#Create Confirm Button
self.confirmButton = QtWidgets.QPushButton(self)
self.confirmButton.setText("OK")
self.confirmButton.clicked.connect(self.createDeck)
#Create Cancel Button
self.cancelButton = QtWidgets.QPushButton(self)
self.cancelButton.setText("Cancel")
self.cancelButton.clicked.connect(self.close)
hboxExportFormat = QtWidgets.QHBoxLayout()
hboxExportFormat.addWidget(self.exportFormat_lbl)
hboxExportFormat.addStretch()
hboxExportFormat.addWidget(self.exportFormat_combo)
hboxExportName = QtWidgets.QHBoxLayout()
hboxExportName.addWidget(self.exportDeckName_lbl)
hboxExportName.addStretch()
hboxExportName.addWidget(self.exportDeckName_combo)
hboxButtonsBottom = QtWidgets.QHBoxLayout()
hboxButtonsBottom.addStretch()
hboxButtonsBottom.addWidget(self.confirmButton)
hboxButtonsBottom.addWidget(self.cancelButton)
#Create The VBoxLayout
mainLayout = QtWidgets.QVBoxLayout(self)
mainLayout.addLayout(hboxExportFormat)
mainLayout.addLayout(hboxExportName)
mainLayout.addLayout(vboxExport_setDelimiter)
mainLayout.addWidget(self.includeMedia_check)
mainLayout.addWidget(self.includeTags_check)
mainLayout.addWidget(self.includeAllSQL_check)
mainLayout.addStretch()
mainLayout.addLayout(hboxButtonsBottom)
def on_combobox_changed(self, i):
if i == ".TXT":
self.exportSetDelimiter_lbl.show()
self.exportSetDelimiter_txt.show()
self.includeMedia_check.show()
self.includeTags_check.show()
self.includeAllSQL_check.hide()
elif i == ".CSV":
self.exportSetDelimiter_lbl.hide()
self.exportSetDelimiter_txt.hide()
self.includeMedia_check.show()
self.includeTags_check.show()
self.includeAllSQL_check.hide()
elif i == ".DB":
self.exportSetDelimiter_lbl.hide()
self.exportSetDelimiter_txt.hide()
self.includeMedia_check.show()
self.includeTags_check.show()
self.includeAllSQL_check.show()
def createDeck(self):
print("Exported Sucessfully")
self.close()
#Create A Windows
app = QtWidgets.QApplication(sys.argv)
window = ExportDialog("B1 Biology")
window.show()
sys.exit(app.exec_())
This is my first question, so if you need any additional information, I will add it in. Any help would be much appreciated. Thank you!
When a combobox is newly created, it has an invalid current index (-1) and no current text set. As soon as the first item is added, the index is automatically updated to 0 and the current text changes to that of the item.
You've connected to the currentTextChanged signal before adding new items, and since the function currentTextChanged assumes that the whole ui has been already created (including exportSetDelimiter_lbl), you get the attribute error.
While there's no rule for the placing of signal connections, it's usually a good habit to group all connections at the end of the function that creates them, or anyway, ensure that everything required by their connection has already been created.
So, just move the signal connection at the end of initUI and everything will work fine.
Well... No. Because you didn't set a central widget for the main window and tried to set the layout on it (which is not allowed, since a QMainWindow has a private and unaccessible layout).
Add a QWidget, call self.setCentralWidget(someWidget) and create the layout for that widget.
So I'm creating an image gallery browser in PYQT5.
I can choose a directory and load the image file icons in a scrollable widget like so:
If there is less than 20 or so images in the directory, it works fine. However when there's more than that the image labels for some reason don't show:
If I take a few of those images that aren't showing and put them into a new folder on their own, then try to load only those images, it works, only if the application hasn't already tried to load them before hand and failed, otherwise, the empty square happens again.
So this seems to me to be some sort of framework/memory limitation? Can anyone shed some light on this?
Here is my code:
# MainWindow Set-Up : Creating Widgets and Layouts
class ClassUi(object):
def setup(self, MainW):
MainW.setObjectName("MainW")
MainW.resize(400,500)
self.mainlayout = QtWidgets.QVBoxLayout()
self.centralwidget = QtWidgets.QWidget(MainW)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
self.centralwidget.setSizePolicy(sizePolicy)
self.centralwidget.setLayout(self.mainlayout)
MainW.setCentralWidget(self.centralwidget)
#direcwidget is a container widget for the top part of the program where a directory is chosen
self.direcwidget = QtWidgets.QWidget()
self.direclayout = QtWidgets.QGridLayout()
self.direcwidget.setLayout(self.direclayout)
self.mainlayout.addWidget(self.direcwidget)
self.opdirbut = QtWidgets.QPushButton() #Button that opens directory dialog when pressed
self.opdirbut.setText("Choose")
self.opdirbut.setFixedSize(50,50)
self.linepath = QtWidgets.QLineEdit() #Line Edit that displays current directory
self.linepath.setText(os.getcwd())
self.backpath = QtWidgets.QPushButton() #Button that changes directory to parent directory of the current one
self.backpath.setFixedSize(20,20)
self.backpath.setText("^")
#Positioning of widgets inside widget container direcwidget
self.direclayout.addWidget(self.opdirbut, 0,0, 2, 1)
self.direclayout.addWidget(self.linepath, 0,2, 1, 3)
self.direclayout.addWidget(self.backpath, 1,4, 1, 1)
#Scrollwidget is the area wherein a container widget widgetforscroll holds all image icons in a grid
self.scrollwidget = QtWidgets.QScrollArea()
self.mainlayout.addWidget(self.scrollwidget)
self.scrollwidget.setWidgetResizable(True)
self.scrollwidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollgrid = QtWidgets.QGridLayout()
self.widgetforscroll = QtWidgets.QWidget()
self.widgetforscroll.setLayout(self.scrollgrid)
self.scrollwidget.setWidget(self.widgetforscroll)
#Contains logic of program
class MainWindow(QtWidgets.QMainWindow, ClassUi):
def __init__(self):
super().__init__()
self.setup(self)
#Counter variables for keeping track of where to layout items
self.picturerow = 0
self.picturecolumn = 0
self.howmany = 0
#Assigns class methods to directory buttons
self.opdirbut.clicked.connect(self.opdial)
self.backpath.clicked.connect(self.uppath)
# Each time this function is called, a new widget called newwidget is created containing "pic" in a pixmap label and a text label and layed out
# on the widgetforscroll widget through its scrollgrid layout. Each time the function is called, picture column increments by one at the end of the function
# when all the columns in a row are filled, picture column is reset to 0 and and picture row is incremented. Picture row and picture column are used in positioning
# the newwidgets in the scrollgrid.
def addpicture(self, pic):
if self.picturecolumn == 3:
self.picturecolumn = 0
self.picturerow += 1
self.howmany += 1
#newwidget is object of picwidg class containing pixmap and text label
newwidget = picwidg(self.howmany, pic)
#This function was not required to be created, it was only created for the purpose of the Qtimer singleshot implementation.
#The newwidget is being positioned on the scrollgrid layout here.
def addnewone(lyout,nw,rw,cl):
lyout.addWidget(nw, rw, cl)
QtCore.QTimer.singleShot(
self.howmany*500,
lambda sc=self.scrollgrid, nr = newwidget, ow = self.picturerow, mn=self.picturecolumn : addnewone(sc,nr,ow,mn)
)
#Incrementing column by 1 for the next time function is called
self.picturecolumn += 1
#This is the function connected to the choose dialog button. It opens a QFileDialog window which allows you to only choose a directory folder.
#When the folder is chosen:
# 1: The linepath text is set the to the new directory
# 2: Any previous picwidg objects are cleared from the scrollgrid layout
# 3: Picture column and picture row variables are reset for positioning
# 4: A for loop scans the new directory for files with .jpg or .png extensions
# 5: The addpicture method is called with the filename as the argument
def opdial(self):
dialogbox = dialog()
try:
os.chdir(dialogbox.getExistingDirectory(options=QtWidgets.QFileDialog.DontUseNativeDialog))
self.linepath.setText(os.getcwd())
for i in reversed(range(self.scrollgrid.count())):
widgetToRemove = self.scrollgrid.itemAt(i).widget()
# remove it from the layout list
self.scrollgrid.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
self.picturecolumn =0
self.picturerow =0
self.howmany = 0
for a, b, c in os.walk(os.getcwd()):
for i in c:
if i[-4:].lower() == ".png" or i[-4:].lower() == ".jpg":
self.addpicture(i)
except:
pass
#This is the function for reaching the parent directory. It works very similar to the above function, the only difference
#being that instead of grabbing a new directory from a QFileDialog, the directory processed is taken from the current linepath text
#and goes to the parent directory instead, then removes widgets from the scrolllayout and adds new pictures to the scrolllayout
def uppath(self):
newpath = os.path.dirname(self.linepath.text())
os.chdir(newpath)
self.linepath.setText(newpath)
for i in reversed(range(self.scrollgrid.count())):
widgetToRemove = self.scrollgrid.itemAt(i).widget()
# remove it from the layout list
self.scrollgrid.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
self.picturecolumn = 0
self.picturerow = 0
self.howmany = 0
for a, b, c in os.walk(os.getcwd()):
for i in c:
# print(i[-4:].lower())
if i[-4:].lower() == ".png" or i[-4:].lower() == ".jpg":
self.addpicture(i)
# This is the class where newwidget instances are created
# Here 2 labels are created, one for the image, one for the text and packed in a vertical layout
class picwidg(QtWidgets.QWidget):
whoshover = None
picwidglist =[]
def __init__(self, numb, pic):
super().__init__()
self.setMouseTracking(True)
self.numb = numb
self.pic = pic
picwidg.picwidglist.append(self)
SizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
newwidgetlayout = QtWidgets.QVBoxLayout()
self.setLayout(newwidgetlayout)
self.setSizePolicy(SizePolicy)
self.setMinimumSize(QtCore.QSize(115, 140))
self.setMaximumSize(QtCore.QSize(115, 140))
#Pic Label
self.newpic = QtWidgets.QLabel()
QtCore.QTimer.singleShot(self.numb*500, self.addingnewpic)
self.newpic.setScaledContents(True)
self.newpic.setSizePolicy(SizePolicy)
self.newpic.setGeometry(0, 0, 100, 100)
self.newpic.setStyleSheet("border:1px solid gray")
#Picture text label
self.newtext = QtWidgets.QLabel()
font_metrics = QtGui.QFontMetrics(self.font())
self.newtext.setAlignment(QtCore.Qt.AlignCenter)
elided_text = font_metrics.elidedText(pic, QtCore.Qt.ElideRight, 100)
self.newtext.setText(elided_text)
newwidgetlayout.addWidget(self.newpic)
newwidgetlayout.addWidget(self.newtext)
def addingnewpic(self):
self.newpic.setPixmap(QtGui.QPixmap(self.pic))
#Class for QFileDialog for selecting only directories
class dialog(QtWidgets.QFileDialog):
def __init__(self):
super().__init__()
self.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
self.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True)
self.setOption(QtWidgets.QFileDialog.ShowDirsOnly, False)
if __name__ == "__main__" :
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
If you want to show a lot of QPixmap then it is not optimal to use a lot of QLabel, in that case it is better to use a QListView (or QListWidget) since it handles memory better.
In your code you add and remove QLabels but in the case of the model only items are added or removed and the view is repainted avoiding the excessive use of memory.
Considering the above I have implemented the following solution:
import os
from PyQt5 import QtCore, QtGui, QtWidgets
ICON_SIZE = 100
class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
option.text = option.fontMetrics.elidedText(
index.data(), QtCore.Qt.ElideRight, ICON_SIZE
)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.choose_btn = QtWidgets.QPushButton(
self.tr("Choose"), clicked=self.on_choose_btn_clicked
)
self.choose_btn.setFixedSize(50, 50)
self.path_le = QtWidgets.QLineEdit()
self.back_btn = QtWidgets.QPushButton(
self.tr("^"), clicked=self.on_back_btn_clicked
)
self.back_btn.setFixedSize(20, 20)
self.pixmap_lw = QtWidgets.QListWidget(
viewMode=QtWidgets.QListView.IconMode,
iconSize=ICON_SIZE * QtCore.QSize(1, 1),
movement=QtWidgets.QListView.Static,
resizeMode=QtWidgets.QListView.Adjust,
)
delegate = StyledItemDelegate(self.pixmap_lw)
self.pixmap_lw.setItemDelegate(delegate)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
grid_layout = QtWidgets.QGridLayout(central_widget)
grid_layout.addWidget(self.choose_btn, 0, 0, 2, 1)
grid_layout.addWidget(self.path_le, 0, 1)
grid_layout.addWidget(self.back_btn, 1, 1, alignment=QtCore.Qt.AlignRight)
grid_layout.addWidget(self.pixmap_lw, 2, 0, 1, 2)
self.resize(640, 480)
self.timer_loading = QtCore.QTimer(interval=50, timeout=self.load_image)
self.filenames_iterator = None
#QtCore.pyqtSlot()
def on_choose_btn_clicked(self):
directory = QtWidgets.QFileDialog.getExistingDirectory(
options=QtWidgets.QFileDialog.DontUseNativeDialog
)
if directory:
self.start_loading(directory)
#QtCore.pyqtSlot()
def on_back_btn_clicked(self):
directory = os.path.dirname(self.path_le.text())
self.start_loading(directory)
def start_loading(self, directory):
if self.timer_loading.isActive():
self.timer_loading.stop()
self.path_le.setText(directory)
self.filenames_iterator = self.load_images(directory)
self.pixmap_lw.clear()
self.timer_loading.start()
#QtCore.pyqtSlot()
def load_image(self):
try:
filename = next(self.filenames_iterator)
except StopIteration:
self.timer_loading.stop()
else:
name = os.path.basename(filename)
it = QtWidgets.QListWidgetItem(name)
it.setIcon(QtGui.QIcon(filename))
self.pixmap_lw.addItem(it)
def load_images(self, directory):
it = QtCore.QDirIterator(
directory,
["*.jpg", "*.png"],
QtCore.QDir.Files,
QtCore.QDirIterator.Subdirectories,
)
while it.hasNext():
filename = it.next()
yield filename
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I have an application where upon start up the user is presented with a dialog to chose number of 'objects' required. This then generates necessary objects in the main window using a for loop (i.e. object1, object2, etc.). I want to move this selection into the main window so that this can be changed without the need to restart the application. I have no idea how to approach this as I'm not sure how to dynamically create/destroy once the application is running. Here's an example code that generates tabs in a tab widget with some elements in each tab.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class SelectionWindow(QDialog):
def __init__(self):
QDialog.__init__(self)
self.settings = QSettings('Example', 'Example')
self.numberOfTabs = QSpinBox(value = self.settings.value('numberOfTabs', type=int, defaultValue = 3), minimum = 1)
self.layout = QFormLayout(self)
self.button = QPushButton(text = 'OK', clicked = self.buttonClicked)
self.layout.addRow('Select number of tabs', self.numberOfTabs)
self.layout.addRow(self.button)
def buttonClicked(self):
self.settings.setValue('numberOfTabs', self.numberOfTabs.value())
self.accept()
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.settings = QSettings('Example', 'Example')
self.tabs = self.settings.value('numberOfTabs', type = int)
self.tabWidget = QTabWidget()
for i in range(1, self.tabs + 1):
exec(('self.tab{0} = QWidget()').format(i))
exec(("self.tabWidget.addTab(self.tab{0}, 'Tab{0}')").format(i))
exec(('self.lineEdit{0} = QLineEdit()').format(i))
exec(('self.spinBox{0} = QSpinBox()').format(i))
exec(('self.checkBox{0} = QCheckBox()').format(i))
exec(('self.layout{0} = QFormLayout(self.tab{0})').format(i))
exec(("self.layout{0}.addRow('Name', self.lineEdit{0})").format(i))
exec(("self.layout{0}.addRow('Value', self.spinBox{0})").format(i))
exec(("self.layout{0}.addRow('On/Off', self.checkBox{0})").format(i))
self.setCentralWidget(self.tabWidget)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
dialog = SelectionWindow()
dialog.show()
if dialog.exec_() == SelectionWindow.Accepted:
mainwindow = MainWindow()
mainwindow.show()
sys.exit(app.exec_())
First of all, you should never use exec for things like these. Besides the security issues of using exec, it also makes your code less readable (and then much harder to debug) and hard to interact with.
A better (and more "elegant") solution is to use a common function to create tabs and, most importantly, setattr.
Also, you shouldn't use QSettings in this way, as it is mostly intended for cross-session persistent data, not to initialize an interface. For that case, you should just override the exec() method of the dialog and initialize the main window with that value as an argument.
And, even if it was the case (but I suggest you to avoid the above approach anyway), remember that to make settings persistent, at least organizationName and applicationName must be set.
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.settings = QSettings('Example', 'Example')
# this value does not need to be a persistent instance attribute
tabCount = self.settings.value('numberOfTabs', type = int)
# create a main widget for the whole interface
central = QWidget()
mainLayout = QVBoxLayout(central)
tabCountSpin = QSpinBox(minimum=1)
mainLayout.addWidget(tabCountSpin)
tabCountSpin.setValue(tabCount)
tabCountSpin.valueChanged.connect(self.tabCountChanged)
self.tabWidget = QTabWidget()
mainLayout.addWidget(self.tabWidget)
for t in range(tabCount):
self.createTab(t)
self.setCentralWidget(central)
def createTab(self, t):
t += 1
tab = QWidget()
self.tabWidget.addTab(tab, 'Tab{}'.format(t))
layout = QFormLayout(tab)
# create all the widgets
lineEdit = QLineEdit()
spinBox = QSpinBox()
checkBox = QCheckBox()
# add them to the layout
layout.addRow('Name', lineEdit)
layout.addRow('Value', spinBox)
layout.addRow('On/Off', checkBox)
# keeping a "text" reference to the widget is useful, but not for
# everything, as tab can be accessed like this:
# tab = self.tabWidget.widget(index)
# and so its layout:
# tab.layout()
setattr(tab, 'lineEdit{}'.format(t), lineEdit)
setattr(tab, 'spinBox{}'.format(t), spinBox)
setattr(tab, 'checkBox{}'.format(t), checkBox)
def tabCountChanged(self, count):
if count == self.tabWidget.count():
return
elif count < self.tabWidget.count():
while self.tabWidget.count() > count:
# note that I'm not deleting the python reference to each object;
# you should use "del" for both the tab and its children
self.tabWidget.removeTab(count)
else:
for t in range(self.tabWidget.count(), count):
self.createTab(t)
UPDATE I made a function to get the text from QLineEdit in the logingui file, and it works. I have no idea why the same function wouldn't work if imported from a different file.
I am trying to get text from QLineEdit on a button click, I have 2 files, logingui and loginlogic. Both the files import each other. Here's the logingui's code
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import login.loginlogic
class LoginForm(QWidget):
def __init__(self):
QWidget.__init__(self, parent=None)
object = login.loginlogic
formLayout = QFormLayout()
# vboxlayout = QVBoxLayout()
serifFont = QFont("Arial", 10)
unamelbl = QLabel("Username")
unamelbl.setFont(serifFont)
pwdlbl = QLabel("Password")
pwdlbl.setFont(serifFont)
self.unamele = QLineEdit()
self.pwdle = QLineEdit()
self.unamele.setPlaceholderText("Username")
self.pwdle.setPlaceholderText("Password")
self.loginButton = QPushButton("Login")
self.loginButton.setStyleSheet("background-color: #99ff99; font-size: 15px;")
self.loginButton.setFont(serifFont)
self.loginButton.clicked.connect(object.handleLogin)
formLayout.addRow(unamelbl)
formLayout.addRow(self.unamele)
formLayout.addRow(pwdlbl)
formLayout.addRow(self.pwdle)
formLayout.addRow(self.loginButton)
formLayout.setSpacing(20)
self.setLayout(formLayout)
self.setStyleSheet("background-color: rgb(255,255,255)")
self.setMinimumSize(420, 320)
self.setMaximumSize(420, 320)
self.setContentsMargins(60, 50, 60, 50)
self.setWindowIcon(QIcon("favicon.ico"))
self.show()
def handlelogin(self):
u = self.unamele.text()
print(u)
if __name__ == '__main__':
app = QApplication(sys.argv)
form = LoginForm()
app.exec_()
here's the code from loginlogic
import login.logingui
class handleLogin():
def __init__(self):
self.obj = login.logingui.LoginForm()
self.username = self.obj.unamele.text()
print("the code did reach here my man ")
print(self.username)
if __name__ == '__main__':
a = handleLogin()
now the output that I get is
your code reached here
*blank line*
I know that's a blank line cause when I click the button again it just leaves an empty line and the reached here text again. Also when I run the logingui, I do write some text in it. Not leaving it blank.
This is a method to copy a word from my textedit, and set it to a new line into my tableview. What i need is: How to change the color of the word that i selected into my textedit? The name of my text edit is "editor", when i copy the word i need change the color of this word, and i dont know how to do it. help please :). With examples please ~~
def addLineTable(self):
row = self.model.rowCount() #create a line into my tableview
self.model.insertRows(row)
column = 0
index = self.model.index(row, column)
tableView = self.TABLE
tableView.setFocus()
tableView.setCurrentIndex(index)
cursor = self.editor.textCursor()
textSelected = cursor.selectedText() #set text to cursor
self.model.setData(index, QVariant(textSelected)) #set text to new tableview line
If I understand your question correctly, you just want to change the color of the text, right?
You can do that by assigning StyleSheets with css to your QWidgets, documentation here.
A sample below:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
self._offset = 200
self._closed = False
self._maxwidth = self.maximumWidth()
self.widget = QtGui.QWidget(self)
self.listbox = QtGui.QListWidget(self.widget)
self.editor = QtGui.QTextEdit(self)
self.editor.setStyleSheet("QTextEdit {color:red}")
layout = QtGui.QHBoxLayout(self)
layout.addWidget(self.widget)
layout.addWidget(self.editor)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.move(500, 300)
window.show()
sys.exit(app.exec_())
Edit
Or you can setStyleSheet to all your QTextEdit, try this:
......
app = QtGui.QApplication(sys.argv)
app.setStyleSheet("QTextEdit {color:red}")
......
You're already getting the QTextCursor. All you need to do is apply a format (QTextCharFormat) to this cursor and the selected text will be formatted accordingly:
def addLineTable(self):
row = self.model.rowCount() #create a line into my tableview
self.model.insertRows(row)
column = 0
index = self.model.index(row, column)
tableView = self.TABLE
tableView.setFocus()
tableView.setCurrentIndex(index)
cursor = self.editor.textCursor()
# get the current format
format = cursor.charFormat()
# modify it
format.setBackground(QtCore.Qt.red)
format.setForeground(QtCore.Qt.blue)
# apply it
cursor.setCharFormat(format)
textSelected = cursor.selectedText() #set text to cursor
self.model.setData(index, QVariant(textSelected)) #set text to new tableview line