When I use "currentIndex()" on - python

I've been stuck on a school assignment for hours because of this one problem. I need to check the index number (AS AN INTEGER) for the currently selected item in a ListWidget.
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox, QListView
from PyQt5.QtGui import QPixmap
import Ui_countries
class MyForm(QMainWindow, Ui_countries.Ui_mainWindow):
# DON'T TOUCH!
def __init__(self, parent=None):
super(MyForm, self).__init__(parent)
self.setupUi(self)
# END DON'T TOUCH
# EVENT HOOKS HERE
self.countryList.itemClicked.connect(self.CountrySelected)
self.actionLoad_Countries.triggered.connect(self.LoadCountries)
self.sqUnits.currentIndexChanged.connect(self.SqUnits)
#self.updatePopulation.itemClicked.connect(self.updateMemory)
# RESPONSES HERE
# def updateMemory(self):
def LoadCountries(self):
global namelist
global populationlist
global arealist
namelist = []
populationlist = []
arealist = []
objFile = open("GUI/countries.txt")
for line in objFile:
line = line.replace("\n","")
lineList = line.split(",")
self.countryList.addItem(lineList[0])
namelist.append(lineList[0])
populationlist.append(lineList[1])
arealist.append(lineList[2])
objFile.close()
def CountrySelected(self,selectedCountryIndex):
QMessageBox.information(self,"Country changed!",selectedCountryIndex.text())
strCountryName = selectedCountryIndex.text()
strCountryName = strCountryName.replace(" ", "_")
imagePixmap = QPixmap(f"GUI/Flags/{strCountryName}")
strCountryName = strCountryName.replace("_", " ")
self.lblCountryName.setText(strCountryName)
self.flag.setPixmap(imagePixmap)
self.flag.resize(imagePixmap.width(),imagePixmap.height())
idx = self.countryList.currentIndex()
# self.populationbox.setText(populationlist[idx])
# selectedCountryIndex.index()
#^^^^^^^^^^^ useful code
print(int(strCountryName))
def SqUnits(self):
QMessageBox.information(self,"Event Received","Please convert between different units.")
if self.sqUnits.currentText() == "Sq. Miles":
self.totalareabox.setText("YAAAAA")
else:
self.totalareabox.setText("YEEEE")
# DON'T TOUCH
if __name__ == "__main__":
app = QApplication(sys.argv)
the_form = MyForm()
the_form.show()
sys.exit(app.exec_())
The area to focus on would be the CountrySelected function. Whenever I try to run idx = self.countryList.currentIndex(), instead of an integer, I get 'PyQt5.QtCore.QModelIndex object at 0x051A6470' if I try to print idx. My instructor wants us to use pyqt, and I have no experience with it, so I'm kinda freaking out!

Figured it out, classmate sent me this: index = self.listWidget.currentRow()
No idea why index didn't work, but alas, tis the nature of doing your assignments one hour before they're due.

Related

Is there a way to only change a part of the text in QTextEdit?

I want to change only a part of my text, basically I want it so that if a user makes a typo my program auto-corrects it. Now my code just resets the whole text to change the typo.
Here is my code
class MainEditor(QtWidgets.QTextEdit):
def __init__(self):
super().__init__()
self.textChanged.connect(self.current_text)
self.just_changed = False
def current_text(self):
if not self.just_changed:
whole = self.toPlainText()
whole = whole.split(' ')
if len(whole) >= 2:
last_word = whole[-2]
# here was some logic I am just taking it as stop and assuming it was typo
correct_word = "stop"
whole[-2] = correct_word
self.just_changed = True
self.setText(' '.join(whole))
else:
self.just_changed = False
As you see it retypes the whole text again to fix one typo is there a way to only change a part of the text in PySide6?
ADDITIONAL INFO:
This class object is then added to a QVBoxLayout and then the QVBoxLayout is added to the main QVBoxLayout and then it is added to QtWidgets.QWidget and I am also using the setHtml feature changing it to bold.
You have to use the QTextCursor to make the modifications, in the following demo if the user writes any of the words "tops", "sstop", "stoop" then it will be corrected to "stop"
import re
from PySide6 import QtWidgets, QtGui
class MainEditor(QtWidgets.QTextEdit):
WORD_REGEX = re.compile(
r"\b[^\d\W]+\b"
) # https://stackoverflow.com/a/29375664/6622587
def __init__(self):
super().__init__()
self.textChanged.connect(self.current_text)
def current_text(self):
position = 0
text = self.toPlainText()
res = self.WORD_REGEX.search(text[position:])
while res:
word = res.group()
correct_word = self.fix_word(word)
position += res.start()
if correct_word:
self.replace_word(position, word, correct_word)
position += len(correct_word)
else:
position += len(word)
text = self.toPlainText()
res = self.WORD_REGEX.search(text[position:])
def replace_word(self, start, word, new_word):
cursor = QtGui.QTextCursor(self.document())
cursor.setPosition(start)
cursor.movePosition(
QtGui.QTextCursor.MoveOperation.Right,
QtGui.QTextCursor.MoveMode.KeepAnchor,
len(word),
)
cursor.deleteChar()
cursor.insertText(new_word)
def fix_word(self, word):
if word in ("tops", "sstop", "stoop"):
return "stop"
def main():
app = QtWidgets.QApplication()
w = MainEditor()
w.show()
app.exec()
if __name__ == "__main__":
main()

Python passing QtDesigner class as dynamic argument to class in external file

I want to be able to pass in any QT class object between two Python classes in separate *.py files. I researched this on-line and within SO before posting. I'm not that skilled in OO or Python.
First py file was created in QT_designer (5.11): rs485ConfigMenu with class Ui_rs485ConfigMenu(object), with from PyQt5 import QtCore, QtGui, QtWidgets. Not touching that code.
I wrote a second python (python 3.5) file with a class that should accept the Ui_rs485ConfigMenu. I know that the second argument for the class is wrong, but I don't know how to pass in the Ui class for any Ui object as needed (e.g., Ui_menu01 vs. Ui_menu02, etc.).
My code for the second, separate python file and its class is:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
widgetList = [ "QPushButton", "QCheckBox", "QDialogButtonBox", "QLineEdit", "QRadioButton", "QComboBox", "QLabel"]
class widgetListMethod( QMainWindow, Ui_menu ):
def __init__(self):
super( widgetListMethod, self ).__init__()
# Ui_mainMenu.__init__(self)
# self.setupUi(self)
def iterThroughWidgets(self):
menuWidgets = {}
i = 0
b = self.mainMenuFrame.children()
#need general menuFrame name for all menus
#need way of checking all instances in widgetList
for w in b:
flag1 = 0
string0 = str(type(w))
string1 = string0.split("PyQt5.QtWidgets.")
string2 = string1[1]
string3 = string2.split("'")
if not set(string3).isdisjoint(widgetList):
widgetText = w.text()
labelValue = widgetText.split("_value")
if isinstance( w, QLabel ) and len( labelValue ) > 1:
#keep only those QLabels that have .value in label
i = i + 1
flag1 = 1
elif not isinstance( w, QLabel ):
i = i + 1
flag1 = 1
if flag1 == 1:
x = w.geometry().x()
y = w.geometry().y()
menuWidgets[i] = [x, y, widgetText, w ]
return menuWidgets
Ui code from QtDesigner alone exceeds length for characters of 3000 by another 3000+. Cannot paste Ui and py code. Happy to send on or provide link from safe-site.

How to select cells in QtableWidget from list of indexes

In a QtableWidget, I would like to store the selected cells while I query a database and return the previously selected cells back to being selected. My refresh of items on the QtableWidget clears the selection. The user can select non-contiguous ranges of cells.
I have no problem getting the selected cells before I refresh the data with QtableWidget.selectedIndexes().
I have tried looping through the list of indexes and using setCurrentIndex but that only leaves me with the last index. I have run out of ideas. How can I restore the selected ranges of cells based on the stored indexes?
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from room_chart import *
from datetime import datetime, timedelta
class Guest_form(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self)
self.ui = Ui_rooms_chart()
self.ui.setupUi(self)
self.build_chart()
self.ui.book.clicked.connect(self.book)
def book(self):
self.indexes = self.ui.room_chart.selectedIndexes()
#Do stuff
self.build_chart()
#This has the right behaviour but only selects the last index
for x in range(len(self.indexes)):
self.ui.room_chart.setCurrentIndex(self.indexes[x])
self.ui.room_chart.setFocus()
def build_chart(self):
self.ui.room_chart.setRowCount(0)
self.ui.room_chart.setColumnCount(0)
col_labels = []
for x in range(8):
current_day = datetime.now() + timedelta(days=x)
col_labels.append(current_day.strftime('%a') + '\n' + current_day.strftime('%d/%m/%y'))
self.ui.room_chart.setColumnCount(len(col_labels))
self.ui.room_chart.setHorizontalHeaderLabels(col_labels)
row_labels = []
for x in range(8):
row_labels.append(str(x))
self.ui.room_chart.setRowCount(len(row_labels))
self.ui.room_chart.setVerticalHeaderLabels(row_labels)
self.button = QPushButton(self.ui.room_chart)
self.button.setText("Push me")
self.ui.room_chart.setCellWidget(0 , 0, self.button)
if __name__=="__main__":
app=QApplication(sys.argv)
myapp = Guest_form()
myapp.show()
sys.exit(app.exec_())
You have to use the select() method of QItemSelectionModel:
def book(self):
persistenIndex = map(QPersistentModelIndex, self.ui.room_chart.selectedIndexes())
#Do stuff
self.build_chart()
for pix in persistenIndex:
ix = QModelIndex(pix)
self.ui.room_chart.selectionModel().select(ix, QItemSelectionModel.Select)
self.ui.room_chart.setFocus()
Note: It converts the QModelIndex to QPersistentModelIndex to avoid problems since it is not known if build_chart() deletes, moves or performs any other action that changes the position of the items.

How can I have a searchable Qlistview in pyqt

I have a QListView which displays a list of items using PyQt in Python. How can I get it to return a qlistview specific item when searched for?
For example, if I have the following Qlistview with 4 items, how can I get the item which contains text = dan? or bring it to the top of the list. Also, the search doesn't need to be completely specific, If I type "da" I'd like it to return dan or items that starts with "da" and possibly bring it to the top of the list
My Qlistview is defined as follows:
from PyQt4 import QtCore, QtGui
import os
import sys
class AppView(QtGui.QDialog):
def __init__(self, parent=None):
super(AppView, self).__init__(parent)
self.resize(400, 400)
self.ShowItemsList()
def ShowItemsList(self):
self.setWindowTitle("List")
buttonBox = QtGui.QDialogButtonBox(self)
buttonBox.setOrientation(QtCore.Qt.Horizontal)
buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
listview = QtGui.QListView(self)
verticalLayout = QtGui.QVBoxLayout(self)
verticalLayout.addWidget(listview)
verticalLayout.addWidget(buttonBox)
buttonBox.accepted.connect(self.close)
model = QtGui.QStandardItemModel(listview)
with open("names-list.txt") as input:
if input is not None:
item = input.readlines()
for line in item:
item = QtGui.QStandardItem(line)
item.setCheckable(True)
item.setCheckState(QtCore.Qt.PartiallyChecked)
model.appendRow(item)
listview.setModel(model)
listview.show()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
view = AppView()
view.show()
sys.exit(app.exec_())
I fixed it like this. I made my model an instance variable beginning with self so that I can access it from another function.
def searchItem(self):
search_string = self.searchEditText.text() # Created a QlineEdit to input search strings
items = self.model.findItems(search_string, QtCore.Qt.MatchStartsWith)
if len(items) > 0:
for item in items:
if search_string:
self.model.takeRow(item.row()) #take row of item
self.model.insertRow(0, item) # and bring it to the top
else:
print "not found"

QCheckBox state change PyQt4

I'm trying to implement a system in PyQt4 where unchecking a checkbox would call function disable_mod and checking it would call enable_mod. But even though state is changing the checkboxes call the initial function they started with. For this case if an already checked box was clicked it'd always keep calling the disable_mod function! I don't understand why is this happening? Can you guys help me out here a little bit? Here's my code:
from PyQt4 import QtCore, QtGui
from os import walk
from os.path import join
import sys
def list_files_regex(dir):
l = []
for (root, dirnames, filenames) in walk(dir):
for d in dirnames:
list_files_regex(join(root, d))
l.extend(filenames)
return l
directory = "J:/test_pack"
directory = join(directory, "/mods")
count = 0
for y in list_files_regex(directory):
print y
count += 1
print count
class ModEdit(QtGui.QMainWindow):
def __init__(self, title, icon, x, y, w, h):
super(ModEdit, self).__init__()
self.setWindowTitle(title)
self.setWindowIcon(QtGui.QIcon(icon))
self.setGeometry(x, y, w, h)
self.choices = []
self.init()
def init(self):
scroll_widget = QtGui.QScrollArea()
sub_widget = QtGui.QWidget()
v_layout = QtGui.QVBoxLayout()
for y in list_files_regex(directory):
tmp = QtGui.QCheckBox(y, self)
tmp.resize(tmp.sizeHint())
if tmp.text()[len(tmp.text()) - 8: len(tmp.text())] != 'disabled':
tmp.setChecked(True)
# if tmp.isChecked() == 0:
# tmp.stateChanged.connect(self.enable_mod)
# if tmp.isChecked():
# tmp.stateChanged.connect(self.disable_mod)
# v_layout.addWidget(tmp)
self.choices.append(tmp)
print self.choices
for choice in self.choices:
v_layout.addWidget(choice)
if choice.isChecked():
choice.stateChanged.connect(self.disable_mod)
else:
choice.stateChanged.connect(self.enable_mod)
sub_widget.setLayout(v_layout)
scroll_widget.setWidget(sub_widget)
self.setCentralWidget(scroll_widget)
self.show()
def enable_mod(self):
print "ENABLE_TEST"
print self.choices[1].isChecked()
def disable_mod(self):
print "DISABLE_TEST"
print self.choices[1].isChecked()
def test(self):
print 'test'
for ch in self.choices:
if ch.isChecked():
ch.stateChanged.connect(self.disable_mod)
else:
ch.stateChanged.connect(self.enable_mod)
class Rename(QtCore.QObject):
enable = QtCore.pyqtSignal
disable = QtCore.pyqtSignal
app = QtGui.QApplication(sys.argv)
ex = ModEdit("Minecraft ModEdit", "ModEdit.png", 64, 64, 640, 480)
sys.exit(app.exec_())
The problem is that you're only connecting the checkbox stateChanged signal once during initialization. After the state of the checkbox changes, you're not disconnecting the signal and reconnecting it to the correct slot.
You'll need to connect the stateChanged signal to an intermediary slot that will decide which function to call based on the checkbox state. Since you're using the same slot for multiple checkboxes, it's probably best to also pass the checkbox to the slot as well.
from functools import partial
def init(self):
...
for tmp in list_of_checkboxes:
enable_slot = partial(self.enable_mod, tmp)
disable_slot = partial(self.disable_mod, tmp)
tmp.stateChanged.connect(lambda x: enable_slot() if x else disable_slot())
def enable_mod(self, checkbox):
print "ENABLE_TEST"
print checkbox.isChecked()
def disable_mod(self, checkbox):
print "DISABLE_TEST"
print checkbox.isChecked()
Alternatively, since we are now passing the checkbox to the slots, you could just use a single slot and check the checkbox state inside the slot
def init(self):
...
for tmp in list_of_checkboxes:
slot = partial(self.enable_disable_mod, tmp)
tmp.stateChanged.connect(lambda x: slot())
def enable_disable_mod(self, checkbox):
if checkbox.isChecked():
...
else:
...

Categories