How to a call method from another class in Python - python

Can anyone tell me how to call add_row method from def test(self): method in User class ?
Now i am using code for call Rows().add_row().I print something in def add_row(self): then it prints but not add widget in screen.
test.py
class User(Popup):
def __init__(self, obj, **kwargs):
super(User, self).__init__(**kwargs)
def test(self):
Rows().add_row()
class narration(BoxLayout):
col_data = ListProperty(["?", "?", "?"])
button_text = StringProperty("")
def __init__(self, **kwargs):
super(narration, self).__init__(**kwargs)
class Rows(BoxLayout):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
def add_row(self):
self.row_count += 1
self.add_widget(narration(button_text=str(self.row_count)))

class User(Popup):
def __init__(self, obj, **kwargs):
super(User, self).__init__(**kwargs)
self.row_obj = obj
def test(self):
self.row_obj.add_row()
class narration(BoxLayout):
col_data = ListProperty(["?", "?", "?"])
button_text = StringProperty("")
def __init__(self, **kwargs):
super(narration, self).__init__(**kwargs)
class Rows(BoxLayout):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
def add_row(self):
self.row_count += 1
self.add_widget(narration(button_text=str(self.row_count)))
rows_obj = Rows()
user_obj = User(rows_obj)
It it not a working code it's just an example But your approach should be something like that.If you don't want to pass object of "Rows" class than make "User" class as a child of "Rows" class using inheritance concept.
class User(Rows,Popup):

I changed your code a little to show you how it's done.
in tmp.py
class Rows(object):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
def add_row(self):
self.row_count += 1
print "Hello"
# self.add_widget(narration(button_text=str(self.row_count)))
class User(Rows):
def __init__(self, obj, **kwargs):
super(User, self).__init__(**kwargs)
def test(self):
self.add_row()
class narration(object):
# col_data = ListProperty(["?", "?", "?"])
# button_text = StringProperty("")
def __init__(self, **kwargs):
super(narration, self).__init__(**kwargs)
I had to comment out some lines in order to get it working.
now, in tmp2.py
from tmp import User
if __name__ == '__main__':
temp = User("H")
temp.test()
# outputs : Hello
What we did is instanciating the User class such as :
class User(Rows):, so when you will call User class, with the proper super() statement, you will be able to use the methods of Rows as you would use it as if it was defined in User class.
So you will call (it has been modified in the code) : self.add_row(), even if add_row() is a method from Rows.

Related

Is it possible to share value between 2 classes inherited from same class - python

Please find the code below
class Base:
def __init__(self, **kwargs):
self.b1 = kwargs['a']
self.b2 = kwargs['b']
class Child1(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child1).__init__(**kwargs)
print(self.b1)
print(self.b2)
def call(self):
self.b1 -= 10
self.b2 -= 20
class Child2(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child2).__init__(**kwargs)
print(self.b1)
print(self.b2)
When I call using the below:
obj1 = Child1(a=20,b=30,c=5)
obj1.call() #output 20, 30
obj2 = Child2(c=5)
I want the output of b1 and b2 to be reflected since obj1 has already changed the value
Please advice
you can do it like this
class Base:
instances = []
def __init__(self, **kwargs):
self.b1 = kwargs['a']
self.b2 = kwargs['b']
Base.instances.append(self)
class Child1(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child1,self).__init__(**kwargs)
print(self.b1)
print(self.b2)
def call(self):
self.b1 -= 10
self.b2 -= 20
class Child2(Base):
def __init__(self, **kwargs):
self.c = kwargs['c']
super(Child2,self).__init__(a = Base.instances[0].b1, b = Base.instances[0].b2)
print(self.b1)
print(self.b2)
obj1 = Child1(a=20,b=30,c=5)
obj1.call()
obj2 = Child2(c=5)
All new instances initiated with Base are saved inside Base.instances. Then you can take the first one and use its b1 and b2 attributes when you create something from Child2 class.

AttributeError: 'botclass' object has no attribute 'loglist'

class botclass(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
def bot(self):
example_error_message = QListWidgetItem("Error")
example_error_message.setForeground(Qt.red)
self.loglist.insertItem(0, error)
class MainPage(QMainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QWidget.__init__(self, *args, **kwargs)
loadUi("uifile.ui", self)
example_working_message = QListWidgetItem("Working")
example_working_message.setForeground(Qt.green)
self.loglist.insertItem(0, example_working_message)
self.thread = QtCore.QThread()
self.botwork = botclass()
self.botwork.moveToThread(self.thread)
self.thread.started.connect(self.botwork.bot)
self.botwork.clicked.connect(self.thread.start)
Error is "AttributeError: 'botclass' object has no attribute 'loglist'"
I'm getting this error when using PyQt5 in Python, how can I solve it? "botclass" will be used with selenium.
How can fix this?
You must not access the GUI from another thread, what you must do is create a signal that sends the text and then in the GUI you create the item:
class BotClass(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
messageChanged = QtCore.pyqtSignal(str)
def bot(self):
self.messageChanged.emit("Error")
class MainPage(QMainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
loadUi("uifile.ui", self)
self.add_item("Working", Qt.green)
self.bot_thread = QtCore.QThread()
self.botwork = BotClass()
self.botwork.messageChanged.connect(self.handle_message_changed)
self.botwork.moveToThread(self.bot_thread)
self.bot_thread.started.connect(self.botwork.bot)
self.<some_button>.clicked.connect(self.bot_thread.start)
def handle_message_changed(self, message):
self.add_item(message, Qt.red)
def add_item(self, message, color):
item = QListWidgetItem(message)
item.setForeground(color)
self.loglist.insertItem(0, item)
To fix this you need to declare loglist in the same class as botclass.
It would be:
class botclass(QtCore.QObject):
def __init__(self):
self.loglist = #what you want loglist to be
progressChanged = QtCore.pyqtSignal(int)
def bot(self):
example_error_message = QListWidgetItem("Error")
example_error_message.setForeground(Qt.red)
self.loglist.insertItem(0, error)
If loglist is already a variable before the class, then do this:
class botclass(QtCore.QObject):
def __init__(self):
global loglist
self.loglist = loglist
progressChanged = QtCore.pyqtSignal(int)
def bot(self):
example_error_message = QListWidgetItem("Error")
example_error_message.setForeground(Qt.red)
self.loglist.insertItem(0, error)
This makes self.loglist = to the global variable loglist.

QSortFilterProxyModel creates blank items

What I'm trying to do: Take items from a model and sort them using a sorting proxy by a different role:
Expected output:
Real output contains blank lines which shouldn't be there:
You can see the empty lines expand the ListView and can even be selected by cursor.
Here's the code that produces this incorrect behaviour:
from PySide2.QtCore import *
from PySide2.QtWidgets import *
import sys
import string
import random
class MyItem:
def __init__(self, name, value):
self.name = name
self.value = value
def __str__(self):
return self.name +" "+ str(self.value)
class MyCustomModel(QAbstractListModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.list = []
def rowCount(self, parent=None):
return len(self.list)
def data(self, index, role):
row = index.row()
if row < 0 or row >= len(self.list):
return None
item = self.list[row]
if role == Qt.DisplayRole:
return str(item)
if role == Qt.UserRole:
return item.value
else:
return None
def add(self, item):
rc = self.rowCount()
self.beginInsertRows(QModelIndex(), rc, rc+1)
self.list.append(item)
self.endInsertRows()
class MyWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.model = MyCustomModel()
self.listView = QListView(self)
self.sortingProxy = QSortFilterProxyModel()
self.sortingProxy.setSourceModel(self.model)
self.sortingProxy.setSortRole(Qt.UserRole)
self.sortingProxy.sort(0, Qt.AscendingOrder)
self.listView.setModel(self.sortingProxy)
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.listView)
self.setLayout(self.layout)
self.show()
# create some random data for the model
for i in range(10):
randomName = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(8)])
self.model.add(MyItem(randomName, random.randint(0, 30)))
app = QApplication(sys.argv)
widget = MyWidget()
app.exec_()
I've tracked down the issue to QSortFilterProxyModel because when it's removed the problem goes away, but the program no longer sorts the data:
from PySide2.QtCore import *
from PySide2.QtWidgets import *
import sys
import string
import random
class MyItem:
def __init__(self, name, value):
self.name = name
self.value = value
def __str__(self):
return self.name +" "+ str(self.value)
class MyCustomModel(QAbstractListModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.list = []
def rowCount(self, parent=None):
return len(self.list)
def data(self, index, role):
row = index.row()
if row < 0 or row >= len(self.list):
return None
item = self.list[row]
if role == Qt.DisplayRole:
return str(item)
if role == Qt.UserRole:
return item.value
else:
return None
def add(self, item):
rc = self.rowCount()
self.beginInsertRows(QModelIndex(), rc, rc+1)
self.list.append(item)
self.endInsertRows()
class MyWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.model = MyCustomModel()
self.listView = QListView(self)
self.listView.setModel(self.model)
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.listView)
self.setLayout(self.layout)
self.show()
# create some random data for the model
for i in range(10):
randomName = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(8)])
self.model.add(MyItem(randomName, random.randint(0, 30)))
app = QApplication(sys.argv)
widget = MyWidget()
app.exec_()
Because the problem seems to be caused by Pyside2/Qt5 code it seems I have no idea how to counter it.
The problem is not the proxy, the problem is caused by the method you use to add items, if you review the docs you must pass the row number from and to where it is added, in this case as only 1 is added then both match , in the general case if n-elements are added, the solution is:
rc = self.rowCount()
self.beginInsertRows(QModelIndex(), rc, rc + n - 1)
So in your case the solution is:
def add(self, item):
rc = self.rowCount()
self.beginInsertRows(QModelIndex(), rc, rc)
self.list.append(item)
self.endInsertRows()

How to get value by clicking on the qslider?

So i am using Pyqt for creating GUI program using Python programming language. And i am trying to get the value of Qslider when clicking it, but i don't understand how...
self.slide.mouseDoubleClickEvent= lambda event: self.slideclicked()
This is how i declare the method when the slide is clicked, and this is the method :
def slideclicked(self):
print(self.slide.value())
I am hoping to get the value where the mouse clicked, but instead i am just getting current value of the Qslider.
A possible solution is to overwrite the mouseDoubleClickEvent method and create a signal that sends that information:
class Slider(QSlider):
pointClicked = pyqtSignal(QPoint)
def mouseDoubleClickEvent(self, event):
self.pointClicked.emit(event.pos())
class Widget(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
self.setLayout(QVBoxLayout())
self.slider = Slider()
self.layout().addWidget(self.slider)
self.slider.pointClicked.connect(lambda p: print(p.x(), p.y()))
If you can not overwrite that method you could use eventFilter:
class ClickedHelper(QObject):
pointClicked = pyqtSignal(QPoint)
def __init__(self, widget, *args, **kwargs):
QObject.__init__(self, parent=widget)
self.obj = widget
self.obj.installEventFilter(self)
def eventFilter(self, obj, event):
if obj == self.obj and event.type() == QEvent.MouseButtonDblClick:
self.pointClicked.emit(event.pos())
return QObject.eventFilter(self, obj, event)
class Widget(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
self.setLayout(QVBoxLayout())
self.slider = QSlider()
self.layout().addWidget(self.slider)
helper = ClickedHelper(self.slider)
helper.pointClicked.connect(lambda p: print(p.x(), p.y()))

How do I add arguments to a subclass in Python 3

class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, color):
self.color = color
fido = Dog(legs = 4, color = "brown")
This would spute out an error message. How would I do something like that where I add parameters to the subclass that doesn't pertain to the superclass.
Try this:
class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, legs, color):
super().__init__(legs)
self.color = color
fido = Dog(legs=4, color="brown")
That's not how inheritance works. When you inherit from another class, the super-class's parameters are not automatically added to the sub-class's parameter list. You must explicitly accept the desired parameters in your sub-class's constructor and pass them on to the super class's constructor:
class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, color, legs):
super().__init__(legs)
self.color = color
fido = Dog(legs = 4, color = "brown")
Here's an example from a tutorial which explains inheritance and shows how to do this. You need to call the parent class's init function as in this similar example from this tutorial:
class Pet(object):
def __init__(self, name, species):
self.name = name
self.species = species
def getName(self):
return self.name
def getSpecies(self):
return self.species
def __str__(self):
return "%s is a %s" % (self.name, self.species)
class Dog(Pet):
def __init__(self, name, chases_cats):
Pet.__init__(self, name, "Dog")
self.chases_cats = chases_cats
def chasesCats(self):
return self.chases_cats
You still have to pass in the legs argument for Dog, and then use super:
class Wolf:
def __init__(self, legs):
self.legs = 4
class Dog(Wolf):
def __init__(self, color, legs):
super().__init__(legs)
self.color = color
fido = Dog(legs = 4, color = "brown")

Categories