Python Forum
Simple printing the text for a QLineEdit
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Simple printing the text for a QLineEdit
#11
Your subclass idea will not work. There is no relationship between the hardware tab object and the enterNewHardware object. The textboxes in the enterNewHardware object are not the same textboxes that are in the hardwareTab.
from PySide2.QtWidgets import QPushButton, QLineEdit, QApplication, \
    QMainWindow, QWidget, QVBoxLayout, QTabWidget
import sys

class mainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.tabForm = QTabWidget()
        self.tabForm.addTab(hardwareTab(), "HARDWARE")
        self.setCentralWidget(self.tabForm)

class hardwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW HARDWARE")
 
        layout = QVBoxLayout(self)
        layout.addWidget(self.snTextBox)
        layout.addWidget(self.enButton)
 
        print('HWT', self)
        print('textbox', self.snTextBox)
        print('text', self.snTextBox.text())

        self.enButton.clicked.connect(newHardware)
 
class newHardware(hardwareTab):
    def __init__(self):
        super().__init__()
        print('NHW', self)
        print('textbox', self.snTextBox)
        print('text', self.snTextBox.text())
 
if __name__ == "__main__":
    APP = QApplication(sys.argv)
    WINDOW = mainWindow()
    WINDOW.show()
    sys.exit(APP.exec_())
Output:
HWT <__main__.hardwareTab(0x28f73018240) at 0x0000028F739FDD00> textbox <PySide2.QtWidgets.QLineEdit(0x28f730188c0) at 0x0000028F739FDD40> text HWT <__main__.newHardware(0x28f730f3b00) at 0x0000028F739FDE80> textbox <PySide2.QtWidgets.QLineEdit(0x28f730f3440) at 0x0000028F739FDF00> text NHW <__main__.newHardware(0x28f730f3b00) at 0x0000028F739FDE80> textbox <PySide2.QtWidgets.QLineEdit(0x28f730f3440) at 0x0000028F739FDF00> text
The first three lines in the output are the hardwareTab object being created. Notice the object ID for the textbox (0x28f730188c0).

When I push the enButton it creates a new newHardware object. This calls the hardwareTab.__init__() and creates a snTextBox widget. It makes a different snTextBox widget (id 0x28f730f3440). Also notice that nothing was printed for snTextBox.text().

To make this work you need to pass the original hardware tab object, the one that has the text boxes that hold the text you entered. This works:
from PySide2.QtWidgets import QPushButton, QLineEdit, QApplication, \
    QMainWindow, QWidget, QVBoxLayout, QTabWidget
import sys
 
class mainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.tabForm = QTabWidget()
        self.tabForm.addTab(hardwareTab(), "HARDWARE")
        self.setCentralWidget(self.tabForm)
 
class hardwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW HARDWARE")
 
        print('HWT', self)
        print('textbox', self.snTextBox)
        print('text', self.snTextBox.text())
 
        layout = QVBoxLayout(self)
        layout.addWidget(self.snTextBox)
        layout.addWidget(self.enButton)
 
        self.enButton.clicked.connect(lambda: newHardware(self))
 
def newHardware(tab):
    print('NHW', tab)
    print('textbox', tab.snTextBox)
    print('text', tab.snTextBox.text())
 
if __name__ == "__main__":
    APP = QApplication(sys.argv)
    WINDOW = mainWindow()
    WINDOW.show()
    sys.exit(APP.exec_())
Output:
HWT <__main__.hardwareTab(0x16a37f56ce0) at 0x0000016A3893DC00> textbox <PySide2.QtWidgets.QLineEdit(0x16a37f56a20) at 0x0000016A3893DC40> text NHW <__main__.hardwareTab(0x16a37f56ce0) at 0x0000016A3893DC00> textbox <PySide2.QtWidgets.QLineEdit(0x16a37f56a20) at 0x0000016A3893DC40> text This is the text I entered
Notice that the object ID's printed in the hardwareTab.__init__() match the ID's of the objects passed to the newHardware() function. These are the QLineEdit objects you are looking for. Also notice that the text I entered in the snTextBox (This is the text I entered) is printed out by the newHardware() function.

Of course the other thing you could do is make the order function a method of the hardwareTab.
from PySide2.QtWidgets import QPushButton, QLineEdit, QApplication, \
    QMainWindow, QWidget, QVBoxLayout, QTabWidget
import sys
 
class mainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.tabForm = QTabWidget()
        self.tabForm.addTab(hardwareTab(), "HARDWARE")
        self.setCentralWidget(self.tabForm)

class hardwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW HARDWARE")
 
        layout = QVBoxLayout(self)
        layout.addWidget(self.snTextBox)
        layout.addWidget(self.enButton)
 
        self.enButton.clicked.connect(self.newHardware)
 
    def newHardware(self):
        print(self.snTextBox.text())
        ## ORDER CODE GOES HERE
 
if __name__ == "__main__":
    APP = QApplication(sys.argv)
    WINDOW = mainWindow()
    WINDOW.show()
    sys.exit(APP.exec_())
Reply
#12
I understand what you're saying but at the same time confused. I thought if a class or function inherited another class then the child class can access any of the objects within the parent class? I thought inheritance was pretty much extending the parent class.

The code you wrote with the lambda function confuses me. To me it seems you're just creating another separate instance of the text boxes? Obviously it works since I see the output and tested the print function in my code and it printed. I just don't understand the code. I tried using the lambda function in my code but the app just closes when clicking the button and no data is entered. Although if I just print the text boxes it does work. But I need that data to be entered into my database. It's hard to debug when the app isn't throwing any error codes.

from PyQt5.QtWidgets import (QLabel, QPushButton, QLineEdit, QApplication, QCheckBox, QMainWindow, QWidget,
                             QVBoxLayout, QTabWidget, QStatusBar)
import pyodbc
import sys


class mainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(385, 323)
        self.setWindowTitle("HARDWARE | SOFTWARE MANAGER")
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)

        self.tabForm = QTabWidget()
        self.tabForm.addTab(hardwareTab(), "HARDWARE")
        self.tabForm.addTab(softwareTab(), "SOFTWARE")
        self.setCentralWidget(self.tabForm)


class hardwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snLabel = QLabel("SERIAL NUMBER")
        self.snTextBox = QLineEdit()
        self.modelLabel = QLabel("MODEL")
        self.modelTextBox = QLineEdit()
        self.userLabel = QLabel("USER")
        self.userTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW HARDWARE")
        self.cfButton = QPushButton("CLEAR FIELDS")
        self.seButton = QPushButton("SEARCH/EDIT HARDWARE")
        self.activeCheckbox = QCheckBox("ACTIVE")
        self.testTextbox = QLineEdit()

        layout = QVBoxLayout(self)
        layout.addWidget(self.snLabel)
        layout.addWidget(self.snTextBox)
        layout.addWidget(self.modelLabel)
        layout.addWidget(self.modelTextBox)
        layout.addWidget(self.userLabel)
        layout.addWidget(self.userTextBox)
        layout.addWidget(self.activeCheckbox)
        layout.addWidget(self.enButton)
        layout.addWidget(self.cfButton)
        layout.addWidget(self.seButton)
        layout.addWidget(self.testTextbox)

        self.enButton.clicked.connect(lambda: enterNewHardware(self))


def enterNewHardware(tab):

    serial_number = tab.snTextBox.text()
    model_name = tab.modelTextBox.text()
    user_name = tab.userTextBox.text()
    test_textbox = tab.testTextbox.text()

    azureServer = "pythonserver5874.database.windows.net"
    azureDB = "inventoryDatabase"
    userName = "na"
    password = "na"
    driver = "{ODBC Driver 17 for SQL Server}"
    connectionString = f"DRIVER={driver};SERVER={azureServer};PORT=1433;DATABASE={azureDB};UID={userName};PWD={password}"
    conn = pyodbc.connect(connectionString)
    cursor = conn.cursor()

    sql_statement = 'INSERT INTO inventoryDatabase.dbo.Hardware(serialNumber, modelName, userName, machineActive) VALUES (?, ?, ?, ?)'
    data = (serial_number, model_name, user_name, test_textbox)

    cursor.execute(sql_statement, data)
    conn.commit()


class softwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snLabel = QLabel("SERIAL NUMBER / KEY")
        self.snTextbox = QLineEdit()
        self.nameLabel = QLabel("APPLICATION NAME")
        self.nameTextBox = QLineEdit()
        self.userLabel = QLabel("USER")
        self.userTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW SOFTWARE")
        self.cfButton = QPushButton("CLEAR FIELDS")
        self.seButton = QPushButton("SEARCH/EDIT SOFTWARE")

        layout = QVBoxLayout(self)
        layout.addWidget(self.snLabel)
        layout.addWidget(self.snTextbox)
        layout.addWidget(self.nameLabel)
        layout.addWidget(self.nameTextBox)
        layout.addWidget(self.userLabel)
        layout.addWidget(self.userTextBox)
        layout.addWidget(self.enButton)
        layout.addWidget(self.cfButton)
        layout.addWidget(self.seButton)


if __name__ == "__main__":
    APP = QApplication(sys.argv)
    WINDOW = mainWindow()
    WINDOW.show()
    sys.exit(APP.exec_())
I don't see how I'm referencing the original text boxes from the hardwareTab class here:

def enterNewHardware(tab):

    serial_number = tab.snTextBox.text()
    model_name = tab.modelTextBox.text()
    user_name = tab.userTextBox.text()
    test_textbox = tab.testTextbox.text()
I understand what I need to do in my head I think it's the coding that is throwing me for a loop.
Reply
#13
A subclass inherits methods from it's superclass. It does not inherit objects.

Unlike C++, Python inheritance is only about methods. When you declared enterNewHardware is a subclass of hardwareTab, enterNewHardware inherited all the methods defined by hardwareTab which inherited all the methods defined by QWidget and so on an so forth all the way back to class object. No instance variables are inherited.

You are probably wondering "What about all the labels and buttons and stuff in hardwareTab. Don't I inherit those? The answer is no. Inheritance does not make instance variables. For proof I subclassed HardwareTab like this and created an instance of the new class.
class EnhancedHardwareTab(HardwareTab):
    def __init__(self):
        self.x = 5
        print(self.x)
Notice that the __init__ method does not call the __init__ method for the superclass. This is a necessary error to make my point.

I set a breakpoint inside the HardwareTab.__init__ method and inside the EnhancedHardwareTab.__init__ method. This is what was returned when I asked for all the instance variables defined in a HardwareTab.
Output:
self.__dict__ {'enButton': <PySide2.QtWidgets.Q...24715E5C0>, 'snTextBox': <PySide2.QtWidgets.Q...24715E500>}
This is what was returned when I asked for all the instance variables defined in an EnhancedHardwareTab.
Output:
self.__dict__ {'x': 5}
EnhancedHardwareTab does not "inherit" the enButton and snTextBox from HardwareTab. But if, inside the EnhancedHardwareTab.__init__ I had called super().__init__() the HardwareTab.__init__ would create those objects for me. If I modify EnhancedHardwareTab to call super().__init__ the "inherited" attributes magically appear.
Output:
self.__dict__ {'enButton': <PySide2.QtWidgets.Q...D0265EC00>, 'snTextBox': <PySide2.QtWidgets.Q...D0265EB40>, 'x': 5}
The attributes common to HardwareTab and EnhancedHardwareTab are not created by inheritance, but rather by calling an inherited method. You might say this is just semantics, but it is very important semantics. Especially when describing why inheritance does not create shared instance variables.

When you created an instance of hardwareTab and added it to the tab view, the hardwareTab.__init__ method created a bunch of QLabels, QLineEdits and a QButton. This is a method/function calling code that creates instances of QtWidgets. When you press the enButton in your code it created an instance of enterNewHardware class. Creating a new instance resulted in calling hardwareTab.__init__, which created a bunch of QLabels, QLineEdits and QButtons. But these are no the same widgets that appear in the hardwareTab you previously created. These were different widgets. The only similarity between the hardwareTab object widgets and the enterNewHardware object widgets is that their attribute names are the same.

What I did in my code was pass the hardwareTab object that you added to the tab control, as an argument to the newHardware function. I didn't pass a new instance of the class, or a new instance of an inherited class. I passed the actual object that contains the widgets you see on the screen. If you doubt me, try this slightly modified code.
from PySide2.QtWidgets import QPushButton, QLineEdit, QApplication, \
    QMainWindow, QWidget, QVBoxLayout, QTabWidget
import sys
  
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.tabForm = QTabWidget()
        self.tabForm.addTab(HardwareTab(), "Hardware")
        self.tabForm.addTab(HardwareTab(), "Software")
        self.setCentralWidget(self.tabForm)
  
class HardwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW HARDWARE")
  
        layout = QVBoxLayout(self)
        layout.addWidget(self.snTextBox)
        layout.addWidget(self.enButton)
  
        self.enButton.clicked.connect(lambda: newHardware(self))
  
def newHardware(tab):
    print(tab.snTextBox.text())
  
if __name__ == "__main__":
    APP = QApplication(sys.argv)
    WINDOW = MainWindow()
    WINDOW.show()
    sys.exit(APP.exec_())
This code creates two instances of the same class. It labels one Hardware and the other Software. Enter text in the Hardware tab and press the button. What get's printed? Do the same thing in the SOftware tab. but enter different text. What get's printed? Switch back and forth between the tabs, pressing the button. Does the print always match the text in the window?

Lambda expressions:
If you want to write GUI programs you need to get comfortable with lambda expressions. Rarely does the signature of a Qt Signal callback match the function I want to call. For example, there is no Qt Signal that I can use for a pushbutton to call a function with a hardwareTab argument. This is where lambda is useful. This code tells the Pushbutton that I want it to call "newHardware" and pass "self" as the first argument.
self.enButton.clicked.connect(lambda: newHardware(self))
Notice that I am using parenthesis and passing an argument. Lambda lets you do this. Normally following the function name with parenthesis would call the function and the return value would be bound to the clicked signal. But the evaluation of a lambda expression is delayed. The expression following the lambda is not evaluated until the button is pressed. This lets me change the signature from what the signal wants to what my function is using. I can describe this in greater detail, but some independent study of lambda expressions and their use would provide greater returns.
thewolf likes this post
Reply
#14
Thanks for the detailed explanation deanhystad. Truth is I have read and viewed videos on classes and subclasses but I was under the impression a subclass not only inherited methods but also all objects and variables within the parent class.

I'm going to have to read your post a few times to make sure I fully understand but basically:

A subclass only inherits the methods(functions within the parent class or inherited class).

or if an outside function(function outside of a class) calls a class, again only inherits the methods of the class being called.

Sometimes it reads like you're referring to an outside function as a subclass in your posts. I may be getting terms mixed up. If an outside function calls a class is it considered a "subclass"?

Just read about the help function and think could help clarify some things.

At this point I think the problem is somewhere in my sql statement since I can print the textboxes clicking the button now but when I try calling the variables I set for them in the sql statement the app just bombs out and closes without any errors.
Reply
#15
I am confused by this

Quote:or if an outside function(function outside of a class) calls a class, again only inherits the methods of the class being called.

Inheritance affects which code runs when a method is called, but it is incorrect to say that calling a method of an object "inherits" something. I can ask a hardwareTab object for it's width and height for example. Your code does not define these methods, but they are defined by QWidget, and because they are methods of a superclass, they get inherited by hardwareTab. So you could say that inheritance affects how a method call is bound, how Python figures out what code to execute, but calling a method does not result in the caller "inheriting" anything.

I think any confusion you have about function calls and inheritance is caused by your enterNewHardware class. In some of your posts enterNewHardware was a function, and then later you made it a class. enterNewHardware() calls a function when enterNewHardware() is a function and it creates an instance of a class when enterNewHardware is a class. As a result, this code does really different things based on if enterNewHardware is a function or a class.
self.enButton.clicked.connect(enterNewHardware)
If enterNewHardware is a function, pressing the button calls the function with no arguments. If enterNewHardware is a class, pressing the button creates a new instance of the class, and enterNewHardware.__init__() is called.
thewolf likes this post
Reply
#16
Thanks for the help deanhystad. I created another function to clear the data out of the text boxes and I think I understand that how that is working now.

At this point the issue is the sql statement and I have searched and tried at least 10 different ways of writing it and it just won't input the data for some reason. Tried different placeholders for the values.

Do you have any idea what might be wrong with my SQL statement? I placed the print functions there just to make sure I was receiving the data from the textboxes and I am.

from PyQt5.QtWidgets import (QLabel, QPushButton, QLineEdit, QApplication, QCheckBox, QMainWindow, QWidget,
                             QVBoxLayout, QTabWidget, QStatusBar)
import pyodbc
import sys


class mainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(385, 323)
        self.setWindowTitle("HARDWARE | SOFTWARE MANAGER")
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)

        self.tabForm = QTabWidget()
        self.tabForm.addTab(hardwareTab(), "HARDWARE")
        self.tabForm.addTab(softwareTab(), "SOFTWARE")
        self.setCentralWidget(self.tabForm)


class hardwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snLabel = QLabel("SERIAL NUMBER")
        self.snTextBox = QLineEdit()
        self.modelLabel = QLabel("MODEL")
        self.modelTextBox = QLineEdit()
        self.userLabel = QLabel("USER")
        self.userTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW HARDWARE")
        self.cfButton = QPushButton("CLEAR FIELDS")
        self.seButton = QPushButton("SEARCH/EDIT HARDWARE")
        self.activeCheckbox = QCheckBox("ACTIVE")
        self.testTextbox = QLineEdit()

        layout = QVBoxLayout(self)
        layout.addWidget(self.snLabel)
        layout.addWidget(self.snTextBox)
        layout.addWidget(self.modelLabel)
        layout.addWidget(self.modelTextBox)
        layout.addWidget(self.userLabel)
        layout.addWidget(self.userTextBox)
        layout.addWidget(self.activeCheckbox)
        layout.addWidget(self.enButton)
        layout.addWidget(self.cfButton)
        layout.addWidget(self.seButton)
        layout.addWidget(self.testTextbox)

        self.enButton.clicked.connect(lambda: enterNewHardware(self))
        self.cfButton.clicked.connect(lambda: clearHardwareFields(self))


class softwareTab(QWidget):
    def __init__(self):
        super().__init__()
        self.snLabel = QLabel("SERIAL NUMBER / KEY")
        self.snTextbox = QLineEdit()
        self.nameLabel = QLabel("APPLICATION NAME")
        self.nameTextBox = QLineEdit()
        self.userLabel = QLabel("USER")
        self.userTextBox = QLineEdit()
        self.enButton = QPushButton("ENTER NEW SOFTWARE")
        self.cfButton = QPushButton("CLEAR FIELDS")
        self.seButton = QPushButton("SEARCH/EDIT SOFTWARE")

        layout = QVBoxLayout(self)
        layout.addWidget(self.snLabel)
        layout.addWidget(self.snTextbox)
        layout.addWidget(self.nameLabel)
        layout.addWidget(self.nameTextBox)
        layout.addWidget(self.userLabel)
        layout.addWidget(self.userTextBox)
        layout.addWidget(self.enButton)
        layout.addWidget(self.cfButton)
        layout.addWidget(self.seButton)


def enterNewHardware(fields):

    serial_number = fields.snTextBox.text()
    model_name = fields.modelTextBox.text()
    user_name = fields.userTextBox.text()
    test_textbox = fields.testTextbox.text()

    print(serial_number)
    print(model_name)
    print(user_name)
    print(test_textbox)

    azureServer = "pythonserver5874.database.windows.net"
    azureDB = "inventoryDatabase"
    userName = "na"
    password = "na"
    driver = "{ODBC Driver 17 for SQL Server}"
    connectionString = f"DRIVER={driver};SERVER={azureServer};PORT=1433;DATABASE={azureDB};UID={userName};PWD={password}"
    conn = pyodbc.connect(connectionString)
    cursor = conn.cursor()

    sql_statement = '''INSERT INTO inventoryDatabase.dbo.Hardware (serialNumber, modelName, userName, machineActive) VALUES (?, ?, ?, ?)'''
    data = (serial_number, model_name, user_name, test_textbox)

    cursor.execute(sql_statement, data)
    conn.commit()


def clearHardwareFields(fields):
    fields.snTextBox.clear()
    fields.modelTextBox.clear()
    fields.userTextBox.clear()
    fields.testTextbox.clear()


if __name__ == "__main__":
    APP = QApplication(sys.argv)
    WINDOW = mainWindow()
    WINDOW.show()
    sys.exit(APP.exec_())
Reply
#17
I suggest you post a new question about pyodbc. This thread is done.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  PyQt5: How to retrieve a QLineEdit by its name ? arbiel 4 563 Oct-21-2020, 02:35 PM
Last Post: arbiel
  Two QlineEdit box, which interrelated GMCobraz 1 463 Aug-14-2020, 07:15 PM
Last Post: deanhystad
  [PyQt] Dynamically add and remove QLineEdit's GMCobraz 3 1,910 Jun-23-2020, 07:01 PM
Last Post: Yoriz
  prompt for input in qlineedit GMCobraz 3 612 Jun-22-2020, 01:51 PM
Last Post: GMCobraz
  [PyQt] display content from left to right in QComboBox or QLineEdit mart79 2 577 May-30-2020, 04:38 PM
Last Post: Axel_Erfurt
  How to loop through all QLineEdit widgets on a form JayCee 6 1,460 Apr-03-2020, 12:15 AM
Last Post: JayCee
  How to accept only float number in QLineEdit input ism 3 6,040 Jan-03-2020, 04:28 PM
Last Post: Denni
  [PyQt] How to clear multiple Qlineedit in a loop mart79 6 2,883 Aug-15-2019, 02:37 PM
Last Post: Denni
  How to validate multiple QLineEdit widgets without addressing them separately? mart79 3 1,098 Aug-08-2019, 12:50 PM
Last Post: Denni

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020