Shihad 20.11.2010 12:59
Есть вопрос! — Как правильно связать сигналы и слоты? (Python/Qt) {Решено}
В процессе написания программы управления моторчиками через Ардуино возникла следующая проблема:Функции, управляющие моторчиками имеют от двух (номер сервопривода, значение) до трех ( + направление вращения) параметров.
Сигнал же идет от ползунка и у него только один параметр - значение.
Есть способ решить эту проблему поизящнее, чем написав отдельную функцию для каждого параметра моторчика?
Покурил Саммерфилда - "Быстрое программирование GUI", но толком не понял, можно ли это сделать с помощью partial. В источниках по Си++ утверждается, что число параметров слота должно быть равно или меньше, чем число параметров сигнала, но верно ли это для Питона?
Собственно функции.
Вызов их из основной программы
1 |
|
Правильным красивым ответом будет использовать функцию partial из модуля functools.
Примерно следующим образом.
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int)"), functools.partial(Zeppelin.Servo, 1))
Всем спасибо за интересную дискуссию, побудившую меня покопаться в Гугле поглубже и вдумчиво покурить Саммерфилда.
Вопрос, а что нужно-то? Не очень понял задачу. Поставить механизм в определенное положение? Тогда датчик положения должен быть.
Вообще - это дирижаблик. У него есть один сервопривод и два моторчика. Все это управляется через Ардуино, сервопривод - непосредственно с выхода, моторы подключены через драйвер.
Задача - сделать управление всем хозяйством через ком-порт.
Главное окно нарисовал. В качестве элементов управления использую ползунки (слайдеры).
Слайдер передает только один параметр - значение. Слот требует два или три параметра.
Как сделать сигнал с несколькими параметрами?
Я вижу два пути - либо переделать класс ползунка так, чтобы он еще номер мотора посылал- похоже, это то, что предлагаете Вы - либо сделать по функции на каждый параметр - отдельно направление, отдельно скорость, отдельно номер.
Оба решения мне кажутся несимпатичными. Можно ли сделать так, чтоб сигнал со значением от ползунка не просто пошел в слот, а пошел в один из несколькиз параметров слота?
Нечто вроде этого
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int)"), Zeppelin.Servo(1,value)
Задача - сделать управление всем хозяйством через ком-порт.
Главное окно нарисовал. В качестве элементов управления использую ползунки (слайдеры).
Слайдер передает только один параметр - значение. Слот требует два или три параметра.
Как сделать сигнал с несколькими параметрами?
Я вижу два пути - либо переделать класс ползунка так, чтобы он еще номер мотора посылал- похоже, это то, что предлагаете Вы - либо сделать по функции на каждый параметр - отдельно направление, отдельно скорость, отдельно номер.
Оба решения мне кажутся несимпатичными. Можно ли сделать так, чтоб сигнал со значением от ползунка не просто пошел в слот, а пошел в один из несколькиз параметров слота?
Нечто вроде этого
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int)"), Zeppelin.Servo(1,value)
Мне кажется, так как Вы хотите, нельзя. Т.е. указать в методе connect значение параметра для слота не получится.
Спасибо. Отрицательный результат - тоже результат.
А никаких функций типа partial или lambda нельзя задействовать? У Саммерфилда они есть, но объяснены не слишком просто.
А никаких функций типа partial или lambda нельзя задействовать? У Саммерфилда они есть, но объяснены не слишком просто.
Не думаю насчет лямбда. А может сделать так?:
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int, int)"), Zeppelin.Servo(num,value)
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int, int)"), Zeppelin.Servo(num,value)
> Можно ли сделать так, чтоб сигнал со значением от ползунка не просто пошел в слот, а пошел в один из несколькиз параметров слота?
как ярый c++, хочу спросить - что пойдет в остальные параметры слота?
как ярый c++, хочу спросить - что пойдет в остальные параметры слота?
Поскольку у аргументов у сигнала по документации должно быть больше или равно количеству аргументов слота, константу некуда вставлять.
И в прототипе метода connect тоже не видно, как бы можно бы было подключить константу.
bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection )
И в прототипе метода connect тоже не видно, как бы можно бы было подключить константу.
bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection )
А так, как вы предложили?
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int, int)"), Zeppelin.Servo(num,value)
Компилятор ругается на несоответствие типов. Возможно, просто неправильно форматирую строку.
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int, int)"), Zeppelin.Servo(num,value)
Компилятор ругается на несоответствие типов. Возможно, просто неправильно форматирую строку.
совсем не очевидно. если уж хочется велосипед - я бы сделал что-то типа на C
void slotOnUpdate(int param1, int param2, int param3) {
static int _p1(0); static int _p2(0); static int p3(0);
if (_p1 != param1) updateParam1Func(param1);
if (_p2 != param2) updateParam2Func(param2);
if (_p3 != param3) updateParam3Func(param3);
_p1 = param1; _p2 = param2; _p3 = param3;
}
Я питон-то только начал изучать, а вы си предлагаете. Не, си - это хорошо. Но для меня рано.
это не важно - суть просто в локальном кешировании старых значений в одном месте - мультиплексор типа ;) а он дергает 3 разных функции в зависимости от того, какое значение изменилось. в результате имеем скрытый от посторонних глаз интерфейс управления супердирижаблем, который втихую можно изменять не затрагивая другую часть программы. внутрь можно добавить обработку еще всех трех значений сразу, если надо.
Интересно. Посмотрю, как у меня получится с драйвером двигателей - сумею ли я поменять направление и скорость? Если уже имеющийся метод не прокатит, с удовольствием воспользуюсь вашим советом.
То, что я написал, явно неправильно, просто хотел передать идею, сделать сигнал с двумя параметрами и слот с двумя параметрами. Но этот сигнал с двумя параметрами тоже нужно дергать откуда-то.
Какое решение получилось?
Какое решение получилось?
Воспользоваться функцией partial из functools. Примерно она делает следующее
def partial(func, arg):
def callme():
return func(arg)
return callme
Вызвав ее так, получаю то, что требовалось.
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int)"), functools.partial(Zeppelin.Servo, 1))
Qt.QObject.connect(form.spinBoxAngle, Qt.SIGNAL("valueChanged(int)"), functools.partial(Zeppelin.Servo, 1))
Заборол значит по питоновски! Поздравляю. А я узнал про functools. Спасибо, буду иметь в виду.
Я как-то пробовал применять паттерны при программировании на Python. ИМХО это неоправданно. Ну или нужны совсем другие паттерны. Для себя я сделал следующий вывод. То, что обычно называется паттернами, придумано для C++/Java, при переносе их в том же самом виде на Python получается слишком все громоздко. На Python, когда пишешь, используя питоновский подход, получается гораздо проще/лучше. На C++/Java просто деваться некуда. А в Python есть много встроенных (или в прилагаемых "батарейках" - библиотеках) средств, которые решают многие, решаемые в паттернах задачи.
К примеру, автор вопроса использовал одну функцию из functools и все заработало. С предлагаемыми паттернами, нужно бы было определить еще один класс.
К примеру, автор вопроса использовал одну функцию из functools и все заработало. С предлагаемыми паттернами, нужно бы было определить еще один класс.
Зависит от того, какие и для чего эти паттерны применялись. То, что "точечная" задача может быть реализована с помощью syntactic sugar или стандартной либы, не отменяет паттернов в разработке ПО. Но и "в лоб" все подряд переносить не стоит конечно. Я привел лишь пример. Как и кто его реализует - не мое дело, но знание паттерна Proxy в данном случае избавило бы от длиннющих вопросов.
Я не спорю, только ИМХО, паттерны (стандартные решения) в Python должны быть другие.
не хочу флудить, но питон судя по описанию - это мультипарадигменный язык общего назначения, как и c++. на вскидку нашлось Design Patterns in Python ;) просто реализовано python-based способами. некоторые отличаются от c++, но возможности предоставляются те же. повторюсь - в этом и суть паттернов IMHO - решать абстракции высокого уровня вне зависимости от языка.
Почему бы доброжелательно не обсудить? При чем тут флуд. Я смотрел и пробовал применять Design Patterns in Python , если мы про одно и то же. Начинал с мнения похожего на Ваше. Но в результате пришел к своей позиции.
Если понимать Design Patterns как стандартные инженерные решения типовых задач, то я за. Но на сегодня есть нюанс. То, что обычно понимают под Design Patterns заточено в первую очередь под C++ и Java. И многие проблемы, которые в них решаются, в Python просто не возникают или лучше их решать "по питоновски". То, что я видел в сети, и что называется Design Patterns in Python - скорее перенос C++ паттернов в питон. Многие вопросы, для которых применяются паттерны в C++, в питоне решаются в одну строчку или библиотечную функцию. А многие вообще не возникают.
Вот такое вот мнение.
С уважением
Евгений
Если понимать Design Patterns как стандартные инженерные решения типовых задач, то я за. Но на сегодня есть нюанс. То, что обычно понимают под Design Patterns заточено в первую очередь под C++ и Java. И многие проблемы, которые в них решаются, в Python просто не возникают или лучше их решать "по питоновски". То, что я видел в сети, и что называется Design Patterns in Python - скорее перенос C++ паттернов в питон. Многие вопросы, для которых применяются паттерны в C++, в питоне решаются в одну строчку или библиотечную функцию. А многие вообще не возникают.
Вот такое вот мнение.
С уважением
Евгений
Спасибо всем за обсуждение.
В настоящий момент я действительно воспользовался готовым враппером из functools. Вообще, по моему скромному, дао питона - "все уже написано до тебя". Это "все" надо собрать и заставить работать вместе.
Но, поскольку мне нужно было не просто решение, а решение красивое (так бы я написал костыль - несколько функций, различающихся только названиями), я благодарен dront78 за указание точки дальнейшего погружения в теорию. Применю сразу, как только смогу.
В настоящий момент я действительно воспользовался готовым враппером из functools. Вообще, по моему скромному, дао питона - "все уже написано до тебя". Это "все" надо собрать и заставить работать вместе.
Но, поскольку мне нужно было не просто решение, а решение красивое (так бы я написал костыль - несколько функций, различающихся только названиями), я благодарен dront78 за указание точки дальнейшего погружения в теорию. Применю сразу, как только смогу.
Не силен в PyQT, но навскидку, что бы попробовал. Передал бы один аргумент, словарь.
Пардон, если неправильно понял задачу.