167 lines
7.2 KiB
Markdown
167 lines
7.2 KiB
Markdown
# Modyfikacja Interfejsu qtdragon_hd w LinuxCNC
|
|
|
|
Data: 2025-12-12
|
|
|
|
## 1. Cel
|
|
|
|
Głównym celem jest dodanie nowej, niestandardowej zakładki z własnymi przyciskami do interfejsu `qtdragon_hd` w LinuxCNC. Kluczowe założenia to:
|
|
- Wykorzystanie wbudowanego, ukrytego przycisku `btn_user`, przeznaczonego do tego celu.
|
|
- Minimalna ingerencja w oryginalne pliki systemowe LinuxCNC.
|
|
- Stworzenie rozwiązania modułowego, gdzie logika i wygląd nowej zakładki są oddzielone od głównego interfejsu.
|
|
|
|
## 2. Podjęte Kroki i Stworzone Pliki
|
|
|
|
1. **Analiza i Strategia:** Zidentyfikowaliśmy, że plik `qtdragon_hd.ui` zawiera przycisk `btn_user` i `QStackedWidget` o nazwie `stackedWidget_mainTab`. Zdecydowaliśmy się nie modyfikować tego pliku, a zamiast tego dynamicznie załadować naszą zakładkę za pomocą niestandardowego handlera w Pythonie.
|
|
|
|
2. **Stworzenie plików w `~/linuxcnc/configs/mayo-mill_hd/`**:
|
|
- `qtvcp/screens/qtdragon_hd/qtdragon_hd.ui`: Lokalna kopia domyślnego pliku UI, stworzona w celu uniknięcia modyfikacji pliku systemowego.
|
|
- `qtvcp/screens/qtdragon_hd/my_user_tab.ui`: Plik UI zawierający *tylko zawartość* naszej nowej zakładki (jeden przycisk testowy).
|
|
- `qtvcp/screens/qtdragon_hd/handler.py`: Plik Pythona z klasą `MyHandler`, która zawiera logikę ładowania zakładki i obsługi przycisków.
|
|
- `custom_postgui.hal`: Plik do podłączenia pinów HAL z interfejsu do logiki maszyny.
|
|
|
|
3. **Konfiguracja:** Zmodyfikowaliśmy plik `mayo-mill.ini`, dodając w sekcji `[DISPLAY]` wpis: `HANDLER = handler.MyHandler`.
|
|
|
|
## 3. Napotkane Problemy i Diagnoza
|
|
|
|
1. **Błąd pinu HAL:** Wystąpił błąd `Pin ... does not exist`, ponieważ `custom_postgui.hal` był przetwarzany, zanim handler w Pythonie zdążył utworzyć pin. Problem nasilał się przez użycie kropki w nazwie pinu, która jest znakiem specjalnym w HAL.
|
|
- **Status:** Problem tymczasowo ominięto przez zakomentowanie linii w `custom_postgui.hal`.
|
|
|
|
2. **Główny Problem: Handler nie był ładowany:** Mimo poprawnego wpisu w `.ini`, logi startowe LinuxCNC pokazały, że system ignorował nasz plik `handler.py` i ładował domyślny handler systemowy (`/usr/share/qtvcp/screens/qtdragon_hd/qtdragon_hd_handler.py`).
|
|
- **Diagnoza:** Nasz plik i klasa `MyHandler` nie były powiązane z domyślnym handlerem. Przez to QTVCP nie traktował go jako rozszerzenia, a jako zupełnie osobny byt, który w tym wypadku został zignorowany na rzecz domyślnej implementacji. Próba zmiany nazwy pliku na `qtdragon_hd_handler.py` spowodowała konflikt i nadpisanie domyślnej logiki, co jest błędne.
|
|
|
|
## 4. Poprawne Rozwiązanie (do wdrożenia)
|
|
|
|
Aby poprawnie rozszerzyć funkcjonalność `qtdragon_hd`, nasz niestandardowy handler musi **dziedziczyć** po klasie handlera domyślnego. W ten sposób zachowujemy całą oryginalną funkcjonalność i tylko dodajemy naszą własną.
|
|
|
|
**Następne kroki do wykonania:**
|
|
|
|
1. Zastąpić zawartość pliku `handler.py` poniższym, **poprawionym kodem**, który implementuje dziedziczenie.
|
|
2. Uruchomić LinuxCNC i zweryfikować, czy zakładka "USER" się pojawiła.
|
|
3. Opcjonalnie: odkomentować linię w `custom_postgui.hal`, aby przetestować działanie pinu HAL.
|
|
|
|
---
|
|
|
|
### Docelowy Kod `handler.py` (z dziedziczeniem)
|
|
|
|
```python
|
|
# -*- coding: utf-8 -*-
|
|
# Plik: handler.py
|
|
|
|
import os
|
|
# Krok 1: Importujemy domyślny handler qtdragon_hd
|
|
from qtvcp.screens.qtdragon_hd import qtdragon_hd_handler
|
|
from qtvcp.core import Info
|
|
from qtvcp.widgets.widget_base import WidgetBase
|
|
from PyQt5.QtWidgets import QPushButton
|
|
|
|
print(">>> WŁASNY HANDLER: Plik handler.py został załadowany.")
|
|
|
|
PATH = Info().get_config_path()
|
|
|
|
# Krok 2: Nasza klasa dziedziczy po 'HandlerClass' z domyślnego handlera
|
|
class MyHandler(qtdragon_hd_handler.HandlerClass):
|
|
"""
|
|
Niestandardowy handler, który ROZSZERZA domyślny handler qtdragon_hd.
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
# Krok 3: Wywołujemy __init__ klasy nadrzędnej
|
|
super(MyHandler, self).__init__(*args, **kwargs)
|
|
print(">>> WŁASNY HANDLER: __init__ wykonany.")
|
|
|
|
def initialized(self):
|
|
# Krok 4: Wywołujemy initialized klasy nadrzędnej, aby cała domyślna logika się wykonała
|
|
super(MyHandler, self).initialized()
|
|
print(">>> WŁASNY HANDLER: Metoda 'initialized' została wywołana (po domyślnym handlerze).")
|
|
|
|
# --- Od tego momentu zaczyna się nasza własna logika ---
|
|
|
|
# Tworzymy nasz własny pin
|
|
self.my_custom_button_pin = self.hal.newpin("wlasny-przycisk_is-on", "HAL_BIT", "out")
|
|
print(f">>> WŁASNY HANDLER: Pin HAL '{self.my_custom_button_pin.name}' został stworzony.")
|
|
|
|
user_tab_ui_file = os.path.join(PATH, 'qtvcp', 'screens', 'qtdragon_hd', 'my_user_tab.ui')
|
|
print(f">>> WŁASNY HANDLER: Sprawdzam ścieżkę: {user_tab_ui_file}")
|
|
|
|
if not os.path.exists(user_tab_ui_file):
|
|
print(">>> WŁASNY HANDLER: BŁĄD! Nie znaleziono pliku my_user_tab.ui.")
|
|
self.widgets.btn_user.setVisible(False)
|
|
return
|
|
|
|
print(">>> WŁASNY HANDLER: Plik my_user_tab.ui znaleziony. Ładuję...")
|
|
|
|
self.user_tab_widget = WidgetBase()
|
|
self.user_tab_widget.load_ui(user_tab_ui_file)
|
|
|
|
main_stack = self.widgets.stackedWidget_mainTab
|
|
user_button = self.widgets.btn_user
|
|
target_index = user_button.property('index')
|
|
|
|
main_stack.insertWidget(target_index, self.user_tab_widget)
|
|
user_button.setVisible(True)
|
|
print(f">>> WŁASNY HANDLER: Zakładka wstawiona na indeks {target_index}, przycisk USER widoczny.")
|
|
|
|
my_button = self.user_tab_widget.findChild(QPushButton, 'moj_wlasny_przycisk_1')
|
|
if my_button:
|
|
my_button.clicked.connect(self.on_my_custom_button_clicked)
|
|
print(">>> WŁASNY HANDLER: Połączono sygnał z 'moj_wlasny_przycisk_1'.")
|
|
|
|
def on_my_custom_button_clicked(self):
|
|
current_state = self.my_custom_button_pin.get()
|
|
self.my_custom_button_pin.set(not current_state)
|
|
print(f">>> WŁASNY HANDLER: Klik! Nowy stan pinu: {not current_state}")
|
|
|
|
```
|
|
|
|
### Plik `my_user_tab.ui`
|
|
|
|
```xml
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<ui version="4.0">
|
|
<class>UserTabWidget</class>
|
|
<widget class="QWidget" name="UserTabWidget">
|
|
<property name="geometry">
|
|
<rect>
|
|
<x>0</x>
|
|
<y>0</y>
|
|
<width>400</width>
|
|
<height>300</height>
|
|
</rect>
|
|
</property>
|
|
<property name="windowTitle">
|
|
<string>Form</string>
|
|
</property>
|
|
<layout class="QVBoxLayout" name="verticalLayout">
|
|
<item>
|
|
<widget class="QPushButton" name="moj_wlasny_przycisk_1">
|
|
<property name="minimumSize">
|
|
<size>
|
|
<width>150</width>
|
|
<height>50</height>
|
|
</size>
|
|
</property>
|
|
<property name="text">
|
|
<string>Mój Własny Przycisk Testowy</string>
|
|
</property>
|
|
</widget>
|
|
</item>
|
|
<item>
|
|
<spacer name="verticalSpacer">
|
|
<property name="orientation">
|
|
<enum>Qt::Vertical</enum>
|
|
</property>
|
|
<property name="sizeHint" stdset="0">
|
|
<size>
|
|
<width>20</width>
|
|
<height>40</height>
|
|
</size>
|
|
</property>
|
|
</spacer>
|
|
</item>
|
|
</layout>
|
|
</widget>
|
|
<resources/>
|
|
<connections/>
|
|
</ui>
|
|
```
|