QTableWidget - przycisk jako item

QTableWidget - przycisk jako item
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Dobry wieczór.

Od wczoraj męczę się z takim pomysłem: Mam w oknie programu obiekt typu QTableWidget. Do tego obiektu wczytuję sobie dane w postaci obiektów QTableWidgetItem.

Obiekt QTableWidget posiada na starcie programu pięć predefiniowanych kolumn oraz zero rzędów. Rzędy pojawiają się kiedy użytkownik użyje opcji wyszukiwania i coś znajdzie (nie ważne co, jakieś dane po prostu).

To wszystko bardzo ładnie działa, ponieważ obiekty typu QTableWidgetItem zawierają dane tekstowe, z którymi nic się nie robi tylko czyta z ekranu.

Ja chciałbym do rzędów, które się pojawią wczytać przyciski, tak żeby wyglądało to następująco:

Kopiuj
// Pionowe kreski reprezentują kolumny tabeli
Dane | Dane | Dane | Przycisk | Przycisk   // rząd nr 1

...

Dane | Dane | Dane | Przycisk | Przycisk   // rząd nr 'n'

// gdzie 'n' to liczba znalezionych przez użytkownika rzędów
// wg jakichś tam kryteriów.

Jak to zrobić w kodzie to wiem, bo robię sobie odpowiednio dużą dynamiczną tablicę obiektów klasy QPushButton i wklejam jej elementy do tabeli na zasadzie:

Kopiuj
this->ui->twWyniki->setCellWidget(0,4,&pb[0]); 
// gdzie obiekt pb[0] to obiekt typu QPushButton, a
// twWyniki to obiekt klasy QTableWidget.

// powoduje to wczytanie do rzędu nr '0', w kolumnie nr '5' przycisku nr [0] z ww tablicy.

Pytanie:
Jak napisać do tego sloty kiedy nie wiem jak duża będzie tak naprawdę tablica przycisków? Chcę żeby te przyciski wyświetlały nowe okno z rysunkiem pobranym z pliku jpg z dysku. Jak zaprogramować sloty do tego skoro liczba przycisków jest zmienna i zależy od ilości rzędów w tabeli wyszukiwania?

Pozdrawiam
Grzegorz

[EDIT]
Zapomniałem dopisać, że działa coś takiego:

Kopiuj
    for(int i = 0; i < 3; i++) // dla trzech przycisków
        connect(&pb[i],SIGNAL(clicked()),pb,SLOT(hide())); // przykładowy slot 'hide()'

tylko teraz chodzi o to, że chcę pojedynczy slot do każdego przycisku, który to slot będzie miał argument, będący ścieżką do jpg na dysku.
Jeżeli każdy przycisk otwiera plik o innej nazwie to musiałbym mieć i-tą ilość takich slotów - tutaj jest pies pogrzebany, bo nie ma sygnału typu clicked(QString tekst).
Pozwalałoby mi to na zdefiniowanie jednego slotu, gdzie ścieżka byłaby przekazywana przez tego stringa.

edytowany 5x, ostatnio: grzesiek51114
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Co wymyśliłem (specjalnie w osobnym poście):

  1. Definiuję sobie taki sygnał:
Kopiuj
 
signals:
    void clicked(QString tekst);
  1. I takie dwa sloty:
Kopiuj
 
void pbclicked(){ emit clicked("Grzegorz"); } // Zamias "Grzegorz" będzie ścieżka do feralnego pliku przypuśćmy.
void test(QString tekst){ this->ui->leTyp->setText(tekst); }; // wstawienie stringa do jakiegoś obiektu QLineEdit
  1. Na końcu robię takie połączenia:
Kopiuj
 
    for(int i = 0; i < 3; i++){
        connect(&pb[i],SIGNAL(clicked()),this,SLOT(pbclicked()));
        connect(this,SIGNAL(clicked(QString)),this,SLOT(test(QString)));
    }

To działa, ale nie wiem... może da się to zrobić jakoś ładniej?

MasterBLB
  • Rejestracja:około 19 lat
  • Ostatnio:9 dni
  • Lokalizacja:Warszawa
  • Postów:1454
0

Da się.
Na dzień dobry wszystkie te QStringi zdefiniuj jako const QString& dzięki czemu unikniesz kopiowania obiektów.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:minuta
0

cały pomysł jest zły (najlepiej zawsze opisywać co chcesz uzyskać, a dopiero w drugim kroku opisać jak próbujesz to uzyskać).
Potrzebujesz delegata, który będzie tworzył przycisk dla danej komórki i zmieniał stan MODELU danych w momencie, gdy coś się ma zmienić.
Patrz:


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 4x, ostatnio: MarekR22
HO
Warto dodać, że proponowane w Twoim poście rozwiązania wymagałyby zastosowania QTableView zamiast QTableWidget.
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Dziękuję za odpowiedź. Z delegatami u mnie jeszcze jest ciężko. Jeszcze tego nie rozumiem ale wgryzę się w temat. Na razie wiem tylko tyle, że jest to coś takiego jak wskaźnik na funkcję :)

MarekR22
mylisz to z delegatami z C#.
grzesiek51114
grzesiek51114
To czym właściwie jest delegat w C++? Z przykładu, który mi wysłałeś wynika, że jest to klasa, która rysuje przycisk i nic więcej. Trochę tego nie rozumiem właśnie.
MarekR22
niestety słowo delegat jest różnie używane przez różne firmy: w .Net jest to wskaźnik na metodę obiektu (w użyciu bardzo podobne do sygnałów z Qt), w iOS są to wskaźniki na coś co implementuje określony protokół (interfejs), a tu to jest coś co odpowiada, za wygląd i zachowanie elementu widoku.
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Zrobiłem!

Nie robiłem do tego delegatów ale obszedłem to przez rzutowanie wskaźnika.
Do sygnału clicked() obiektu QPushButton zrobiłem slot

Kopiuj
void pbTabWcisniety()

o takim ciele:

Kopiuj
 
void OknoGlowne::pbTabWcisniety(){
    QPushButton *pb = qobject_cast<QPushButton *>(sender());
    pb->setText("TRAF!");
}

W tym momencie wskaźnik 'caller' wie, który przycisk został wciśnięty i o to mi chodziło, bo mogę już wykorzystać sobie jego nazwę do poparsowania sobie nazwy pliku z obrazkiem:)

Do tego taka realizacja połączeń (długość pętli oczywiście określona przez listę w programie i ilość przycisków w jednym rzędzie):

Kopiuj
for(int i = 0; i < this->lista.length(); i++){
    for(int j = 0; j < 2; j++){
        connect(&this->pbTab[i][j],SIGNAL(clicked()),this,SLOT(pbTabWcisniety()));
    }
}

Niestety nie rozumiem jeszcze delegatów i musiałem pogłówkować w trochę inny sposób.

Pozdrawiam
Grzegorz

edytowany 3x, ostatnio: grzesiek51114
HO
Na wszelki wypadek proponowałbym w slocie po użyciu castowania dodać if( pb ) a w nim operację na pb - gydyby się okazało że podepnie się slot pod nieodpowiedni obiekt.
grzesiek51114
grzesiek51114
Na pewno trzeba? Zwróć uwagę, że połączenie slot - sygnał gwarantuje, że senderem będzie właśnie push button. Chyba, że jest coś o czym nie wiem.:-)
HO
A gdy np. zmienisz pushbuttony na toolbuttony bo stwierdzisz że są fajniejsze i zapomnisz o castowaniu to w slocie wyląduje NULL i program zacznie się wykrzaczać. Nie ma gwarancji, że od razu będzie jasne gdzie i przez co jest naruszenie pamięci. Jeśli slot będzie miał if to jeśli będzie NULL wtedy nic się nie stanie. Duża szansa, że wpadnie się wtedy na pomysł by sprawdzić slot. Poza tym sprawdzenie wskaźnika czy jest poprawny jest po prostu standardem przyzwoitego kodowania - warto wyrobić sobie taki nawyk.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.