Kyrym
Здесь написано
self.grid = QtGui.QGridLayout()
Почему не написать
grid = QtGui.QGridLayout()
?
Ведь self должен подставится автоматом?
У-у-у как у вас все запущено…..
Вам пожалуй стоит начать с азов так сказать. В пайтоне есть так называемая область видимости переменных. Область видимости тесно связана с операциями присваивания.
Имена появляются в тот момент, когда им впервые присваиваются некоторые значения, и прежде чем имена смогут быть использованы, им необходимо присвоить значения. Поскольку имена не объявляются заранее, интерпретатор Python по местоположению операции присваивания связывает имя с конкретным пространством имен.
По умолчанию все имена, значения которым присваиваются внутри функции, ассоциируются с пространством имен этой функции.
Имена, определяемые внутри инструкции def, видны только программному коду внутри инструкции def. К этим именам нельзя обратиться за пределами функции.
В любом случае область видимости переменной (где она может использоваться) всегда определяется местом, где ей было присвоено значение, и никакого отношения не имеет к месту, откуда была вызвана функция или осуществлена операция изменения объекта.
Подробнее расписано тут например
https://foxford.ru/wiki/informatika/oblasti-vidimosti-peremennyh-v-pythonтеперь давайте посмотрим что получиться если вы напишете
grid = QtGui.QGridLayout()
вместо
self.grid = QtGui.QGridLayout()
grid обьявляеться внутри def __init__ тоесть исходя из вышенаписаного переменная grid связана с областью видимости функции __init__ (локальная переменная), видна только внутри кода __init__ и к ней нельзя обратиться “извне”. А self.grid это уже атрибут инстанса класса GridLayout, и к нему вы можете обратиться из других методов класса, и даже извне класса(поробнее про классы и экземпляры ниже).
Вот дальше у нас есть
def on_start(self):
pole = self.sender() #Лайн едид отправитель сигнала
idx = self.grid.indexOf(pole) # индекс отправителя сигнала
location = self.grid.getItemPosition(idx) # положение в гриде
poleX2 = self.grid.itemAtPosition(location[0],location[1]+1).widget() # соседнее поле
poleX2.setText(pole.text()*2)
print('старт', pole.text()*2)
Оно работает потому что в __init__ мы писали self.grid, тоесть обьявили grid аотрибутом экземпляра класса, и мы можем обратиться к нему как к атрибуту посредством self.grid. А self указывает на то что этот атрибут принадлежит тому же классу из которого мы его вызываем. А если бы указали просто grid то получили бы NameError поскольку метод on_start вообще не вкурсе что вы в __init__ обьявляли какуюто перменную grid.
А если бы вы хотели обратиться к нему извне класса то код выглядел бы вот так:
qb = GridLayout()
location = qb.grid.getItemPosition(5)
Вместо self мы уже пишем перменную указывающую на экземпляр класса.
Определять что использовать self.grid или grid нужно по обстоятельствам. Если к атрибуту нужно обращаться “извне” или из других методов тогда пишем self, если переменная нужна только на время работы функции, то можно обойтись локальной переменной, котороая “исчезнет” после того как функция завершила работу.
Например в последнем варианте можно заменить self.grid на grid потому что grid за пределами __init__ не используеться.
# Python 3. PyQt4
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui, QtCore
sss_vivod = ("background-color: #d0f0c0; font: 10pt 'Arial black'")
sss = ("background-color: #edecbe; font: 10pt")
class MyTextEdit(QtGui.QLineEdit): # создаем свой класс наследуя QLineEdit
def __init__(self, *args, **kwargs):
super().__init__()
self.poles = [] # пустой список ссылок на поля вычислений
def addPole(self, pole):
self.poles.append(pole) # добавляем ссылку на поле в список
print(self.poles)
def valueChange(self,*args):
s=0 # по умолчанию результат = 0
for pole in self.poles:
text = pole.text()
if text:
s+=int(text) # прошлый результат + новое значение
self.setText(str(s))
print(s)
return s
def valueCopy(self,*args):
self.selectAll() # выделяем все
self.copy() # копируем в буфер
class GridLayout(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('Заголовок')
grid = QtGui.QGridLayout()
# ПОЛЯ
n = 6 # строк
m = 2 # столбцов
for i in range(n):
resultPole = MyTextEdit() # поле результата
resultPole.textChanged.connect(self.gl)
resultPole.setStyleSheet(sss_vivod)
grid.addWidget(resultPole,i,m+2)
butCopy = QtGui.QPushButton('Copy')
butCopy.clicked.connect(resultPole.valueCopy)
grid.addWidget(butCopy,i,m+1)
for j in range(m):
sourcePole = QtGui.QLineEdit() # поле данных
sourcePole.setStyleSheet(sss)
grid.addWidget(sourcePole,i,j)
resultPole.addPole(sourcePole) # добавляем ссылку на поле в список
sourcePole.textChanged.connect(resultPole.valueChange)
self.pole_vivod = QtGui.QLineEdit()
grid.addWidget(self.pole_vivod, n+1,m+2)
self.setLayout(grid)
def gl(self, s):
print('приём s = ',s)
self.pole_vivod.setText(str(s))
app = QtGui.QApplication(sys.argv)
qb = GridLayout()
qb.move(250,250)
qb.show()
sys.exit(app.exec_())
Видите, код как работал так и работает, потому что мы используем grid только для расположения виджетов во время __init__. Нам не нужно обращаться к grid из других методов или извне класса.
Теперь давайте посмотрим куда self должен поставляться “автоматом”
вот у нас есть банальный класс
class A(): # Новый класс
x=2 # атрибут x класса А
y=4 # атрибут y класса А
def __init__(self, x, z, n): #метод __init__ класса А
self.x = x # атрибут x экземпляра класса А
self.z = z # атрибут z экземпляра класса А
w = n # локальная переменная
def print(self, num): #метод print класса А
print('self.x + num =',self.x + num)
Для начала можно прочитать хотябы вот это
http://ru.diveintopython.net/fileinfo_class.htmlМетод __init__ вызывается сразу после создания экземпляра класса
Первым аргументом каждого метода класса, включая __init__, всегда является текущий экземпляр класса. Общепринято всегда называть этот аргумент self(Заметте,
общепринято, в приницпе никто не мешает вам использовать любое другое слово). В методе __init__ self ссылается на только что созданный объект, в других методах — на экземпляр класса, для которого метод вызывается. Хотя и необходимо явно указывать self при определении метода, вы его не указываете, когда вызываете метод; Python добавит его автоматически.
Во как. давайте смотреть
>>>
print('A.x=',A.x)
A.x= 2
print('A.y=',A.y)
A.y= 4
print('A.z=',A.z)
Traceback (most recent call last):
File "<модуль1>", line 15, in <module>
AttributeError: type object 'A' has no attribute 'z'
>>>
Как видим есть атрибуты класса, и атрибуты экземпляра класса. Атрибуты класса существуют всегда(без создания экземпляра). “x” и “y” это атрибуты класса. Атрибуты экземпляра существуют только в экземпляре. В нашем примере мы получаем исключение, так как экземпляр класса “А” не создан и атрибут “z” не существует пока.
давайте создадим экземпляр:
a = A(x = 8, z = 22, n = 14) # создаем экземпляр класса А
print('A.x=',A.x)
print('A.y=',A.y)
print('a.x=',a.x)
print('a.y=',a.y)
print('a.z=',a.z)
>>>
A.x= 2
A.y= 4
a.x= 8
a.y= 4
a.z= 22
>>>
Как видим атрибуты A.x и A.y остальсь прежними, поскольку это атрибуты класса “А”, а вот a.x стал равен 8, потому что мы создали экземпляр класса и присвоили атрибуту “х” экземпляра “а” новое значение. Также у экземпляра появился новый атрибут “z”. А откуда взялся a.y, мы же ничего не присвавали? он взялся из атрибутов класса.
Не буду вдаваться в подробности, но когда вы обращаетесь к атрибуту экземпляра, сначала этот атрибут ищеться в экземпляре, и если находится то возвращаеться. Так произошло с нашим а.x. Интерпретатор нашел у экземпляра “а” атрибут “x” и вернул его значение: “8”. Если же найти не удаеться то ищеться в атрибутах класса, так произошло с a.y. Если и у класса нет такого атрибута то рекурсивно ищеться в родительких классов, если и там нет то бросается исключение AttributeError.
Напишем еще:
print('a.w=',a.w)
>>>
Traceback (most recent call last):
File "<модуль1>", line 20, in <module>
AttributeError: 'A' object has no attribute 'w'
“w” локальная перпеменная, она существвовала только пока работал метод __init__. К ней нельзя обратиться “извне”. Мы это рассматривали ранее, когда изучали области видимости.
А вот теперь мы подходим к тому что “self должен подставится автоматом”
У нас есть метод класса print, у него есть два аргумента self и num
мы его можем вызвать вот так:
a = A(x = 8, z = 22, n = 14) # создаем экземпляр класса А
A.print(a,2)
>>>
self.x + num = 10
в качестве первого аргумента мы передаем экземпляр класса, а в качесвте второго число.
внутри мы видим вот такую кострукцию:
print('self.x + num =',self.x + num)
поскольку мы первым аргументом передали “а” то он подставляеться вместо self. В итоге мы получаем на выходе a.x+2( второй аргумент у нас 2), a.x у нас 8, результат = 10.
Но также мы может вызвать метод и вот так:
a.print(2)
>>>
self.x + num = 10
вот в этом случае “self должен подставится автоматом”. Интерпретатор всеравно сделает A.print(self,num) но вместо self “автоматом” подставит “а”, а вместо num двойку.
Надеюсь понятно?
Kyrym
Здесь есть такая строчка:
self.label = QtGui.QLabel('Knowledge only matters', self)
Здесь с селфом вообще не понятно.
еще раз повторюсь, self это “указатель” на экземпляр класса из которого вы вызываете метод.
в данном случае self.label переменная label, атрибут экземпляра класса FontDialog
мы создаем обьект типа QtGui.QLabel и присваиваем его с атрибуту label экземпляра класса FontDialog
теперь читаем документацию к QLabel
http://doc.crossplatform.ru/qt/4.8.x/html-qt/qlabel.html#QLabelи прозреваем
QLabel::QLabel ( const QString & text, QWidget * parent = 0, Qt::WindowFlags f = 0 )
Создаёт метку, которая отображает текст text.
The parent and widget flag f, arguments are passed to the QFrame constructor.
QLabel принимает в качестве первого аргумента текст самого лейбла, а вторым можно указать родительский виджет (не путать с родительским классом)
Соответвенно при таком вызове
self.label = QtGui.QLabel('Knowledge only matters', self)
текстом QLabel-а будет ‘Knowledge only matters’, а родительским виджетом - self: экземпляр класса FontDialog из которого вызвали этот самый QLabel