Listbox mit besseren Helptags

Ein Ärgernis der Xojo-Listbox, das dem Umstand geschuldet ist, dass die Listbox zwar aus nativen Steuerelementen zusammengebastelt ist, aber nicht der nativen Lösung entspricht (NSTableView z.B. auf dem Mac ist zwar ungleich leistungsfähiger, aber auch ungleich schwerer zu beherrschen), besteht darin, dass die CellHelpTags, diese kleinen, sehr praktischen Zettelchen, die beim Verweilen des Mauszeigers über einer Zelle auftauchen, dies zwar tun – aber leider ohne jede Verzögerung.

Das ist weder im Sinne des Anwenders noch im Sinne des Programmierers – man möchte ja erst einmal die Chance bekommen, eine Zeile oder Zelle anzuwählen, ohne dass sich sofort ein HelpTag darüberlegt.

Während ich persönlich die Hoffnung hege, dass im Rahmen der 64 Bit-Fehlerbereinigungen auch die HelpTags einer Überarbeitung unterzogen werden, lehnen die Xojo–Ingenieure aktuell leider eine schnelle Abhilfe ab. Was also tun? Eine eigene Subklasse der Listbox erstellen natürlich – hier ein Vorschlag, der wie üblich dankbar für weitere Verfeinerungen daherkommt!

  • Legen Sie ein neues Desktop-Projekt an und platzieren Sie eine Listbox auf dem Fenster.
  • Wählen Sie die Listbox an, rechtsklicken Sie und suchen Sie aus dem erscheinenden Menü den Eintrag „New Subclass“
    New Subclass
  • Geben Sie der neuen Unterklasse einen hübschen Namen – z.B. „HelpTagListbox“
  • Spendieren Sie dieser Unterklasse zwei Properties: LastColumn und LastRow, beide vom Datentyp Integer mit dem Vorgabewert -1.
  • Erstellen Sie in der Unterklasse einen Eventhandler für den MouseMove-Event.

Warum dieser Event? Er liefert X- und Y-Position des Mauszeigers bezogen auf die Listbox selbst. Umständliche Umrechnungen, die die Mausposition des Systems erhalten und dann den Versatz der Listbox sowie ihrer Position auf dem Fenster beinhalten, entfallen.

Wir werden einfach den CellTag als Zwischenspeicher für den on the fly zu generierenden CellHelpTag verwenden. Wenn Sie den CellTag, der üblicherweise unsichtbar ist, für andere Zwecke benötigen, ließe sich zwar auch der CellHelpTag verwenden. Aber dann blitzt er doch kurzzeitig auf.

Hier der Code für den Event:

Sub MouseMove(X As Integer, Y As Integer) Handles MouseMove
 Dim row As Integer = Me.RowFromXY(x,y)
 Dim column As Integer = Me.ColumnFromXY(x,y)
 If row > -1 And column > -1 Then
  If row <> LastRow Or column <> LastColumn Then
  Dim helptag As Text= Me.CellTag(row, column).StringValue.ToText
  If Not helptag.Empty Then
   Dim helpDict As New Xojo.Core.Dictionary
   helpDict.Value("row") = row
   helpDict.value("column") = column
   helpDict.value("tag") = helptag
   xojo.core.timer.CallLater 1500, AddressOf SetHelptag, helpDict
  End If
  If LastRow > -1 And LastColumn > -1 Then 
   Me.CellHelpTag(LastRow, LastColumn) = ""
  End If
  LastRow = row
  LastColumn = column
  End If
 End If
 RaiseEvent MouseMove x, y
End Sub

Zunächst werden Zeile und Spalte aus den erhaltenen X- und Y-Werten gelesen. Beschreiben diese eine gültige Zelle (sind ihre Werte also größer -1), dann wird der CellTag gelesen – wegen meiner Vorliebe für das Xojo-Framework und der hübschen Text.Empty-Funktion als Text. Natürlich geht das auch als String, der dann auf = „“ geprüft werden sollte.

Um nicht wiederholt denselben CellTag zu lesen und als HelpTag zu schreiben, wird zunächst geprüft, ob die Maus aktuell eine andere Zelle bedeckt als zuvor.

Ist der CellTag dann nicht leer, wird ein Dictionary angelegt. Das deswegen, weil die bald folgende Xojo.Core.Timer.Calllater-Methode nur einen Übergabeparameter erlaubt – wir brauchen aber drei, die im Folgenden geschrieben werden, nämlich mit Zeile, Spalte und dem Text selbst. Mit einer kleinen Verzögerung – hier anderthalb Sekunden – wird dann die Methode SetHelpTag aufgerufen, die das Dictionary als Parameter bekommt. Dazu gleich mehr.

Damit bei einer Mausbewegung auf eine schon gehelptagte Zelle nicht doch gleich wieder der Helptag erscheint, wird dieser – sofern LastRow und LastColumn eine gültige Zelle definieren – wieder gelöscht.

Zu guter Letzt werden Row und Column in den Puffervariablen abgelegt und der MouseMove-Event erneut aufgerufen, damit die Listbox ihn auch weiterhin zur Verfügung stellt.

  • Klicken Sie dazu mit rechter Maustaste auf den Eventhandler und wählen Sie „Create Event Definition from Event“.

Und dann zur Methode, die den HelpTag setzt:

Private Sub SetHelpTag(Helpauto as Auto)
 if me <> nil then
 Dim Helpdict As Xojo.Core.Dictionary = Helpauto
 Dim row As Integer = Helpdict.Value("row")
 Dim column As Integer = Helpdict.value("column")
 Dim Tag As Text = Helpdict.value("tag")
 me.CellHelpTag(row, column) = tag
 End If
End Sub

Diese schaut erst einmal, ob die Listbox noch existiert (das Fenster könnte ja auch geschlossen worden sein), und falls ja, erzeugt sie ein Dictionary aus dem Auto, liest die Werte aus und setzt den HelpTag. Der erscheint dann leider erst nach einer kleinen weiteren Mausbewegung – will man das perfekt machen, müsste man ein kleines Extrafenster einblenden, also den HelpTag selbst nachbauen. Ich denke aber, dass diese Funktion in vielen Fällen so ausreichend ist – und wenn nicht: Überraschen Sie mich gerne mit einer besseren Lösung!

Das wäre es schon fast, wenn da nicht der Sonderfall sein könnte, dass die Listbox zwischenzeitlich neu aufgebaut werden könnte. Wir bedienen uns eines Method Overrides, überschreiben also eine Funktion der Listbox:

Public Sub DeleteAllRows()
 xojo.core.Timer.CancelCall AddressOf SetHelpTag
 If LastRow >-1 And LastColumn >-1 Then
  me.CellHelpTag(lastrow, LastColumn) = ""
 End If
 Me.LastRow = -1
 me.LastColumn = -1
 Super.DeleteAllRows
End Sub

Wird demzufolge DeleteAllRows aufgerufen, stornieren wir den Timer und löschen ggf. den letzten HelpTag. Danach werden die Puffervariablen auf ihren Vorgabewert -1 gesetzt, und erst dann wird mittels Super die eigentliche DeleteAllRows-Methode aufgerufen.

  • Setzen Sie nun noch die Klasse der im Fenster angelegten Listbox auf die neue Unterklasse und befüllen Sie sie probehalber mal mit Werten, wobei Sie beliebige CellTags setzen. Wenn Sie sich diese Arbeit sparen wollen: Hier ist das Demoprojekt (das nur die 3.Spalte für HelpTags verwendet).

Update

Ein Bug im 64 Bit-Framework von Xojo verhindert die Darstellung von HelpTags auf macOS, wenn die App für 64 Bit kompiliert wurde. Im Xojo-Forum hat Marco Hof einen sehr hübschen Workaround freigegeben, den ich – Dank und Lob für die gelungene Umsetzung! – in diesem erweiterten Projekt  integriert habe. Dazu noch ein Fix, damit es keine Probleme mit Windows gibt und keine Compiler-Warnungen ausgegeben werden. Link zum Forum-Thread und Credits befinden sich im MHMouseTip-Modul.

3 Gedanken zu “Listbox mit besseren Helptags

  1. Also, die NSTableView ist ziemlich leicht zu beherrschen mit der ListBoxTV, die ich für MBS-Plugins machte, denn die bildet Xojos ListBox-API fast vollständig nach.
    Und wenn jemand eine declares-Version von NSTableView hat, könnte man meinen Code sicher auch dafür umschreiben.

    Gefällt mir

    1. Ich brauche mal etwas Zeit, um an der AppleLib zu arbeiten – da gab es schon eine TableView, aber ich muss diese noch in die neue Hierarchie drücken. Wenn’s soweit ist, gebe ich dir Bescheid und würde mich freuen, wenn wir zusammen dran arbeiten könnten.

      Gefällt mir

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s