Frage zu CListCtrl-Tooltips
-
Ich glaub, ich verstehe deine Antwort nicht.
Den Tooltip für das ganze Control setzen ? Ich brauch nur in 2 Spalten (13. und 14. Spalte) einen Tooltip, für die restlichen nicht.
Oder anders gesagt: wie kann ich das lösen ?
Tut mir leid, aber verstehe ich noch nicht ganz.
-
1. Du kannst nicht für Spalten einen Tooltip setzen. Was passiert wen das Control rollt (horizontal)?
2. Setze das Tooltip für das ganze Control. Wenn der Tooltip angefordert wird, dann kanst Du selber entscheiden, ob Du Infos liefern willst oder nicht. HitTest sagt die Zeile und Subitem...
Bei allen anderen Spalten lieferst Du einfach keine Info.
-
Naja, wie soll ich sagen ?
Ich hab eine Klasse, die von CListCtrl abgeleitet ist. Wenn es soweit ist, dann setze ich ein Tooltip-Text.
Das ist aber nichts anderes, als dass ich den gewünschten Text in eine CMapStringToString einfüge.
Und das mache ich für 2 Spalten (gebe also Zeile und Spalte an und diese beiden Angaben mit 100 multipliziert, ist dann mein eindeutiger Key für den Eintrag in der Map).Und dann habe ich die schon gezeigten Methoden (OnToolHitTest und OnToolTipText), mit denen ich ermittle, in welcher Zeile und Spalte der Cursor steht und mit der anderen hole ich den Text für eine der beiden Spalten, wenn der Cursor in einer der beiden ist.
Habe dann noch GetToolTipText, der ich die zuvor ermittelte Zeile und Spalte übergebe und dann nach Erstellung eines Keys für die Map in der Map schaue, ob zu diesem Key ein Eintrag (bzw. Tooltip-Text) existiert. Wenn ja, wird er angezeigt.
---------
Mein Problem liegt eher darin, dass ich neue Daten immer in die 1.Zeile der Liste einfüge, damit aber immer wieder den Tooltip-Text der zuvor eingefügten Zeile überschreibe.
Ich will aber für jede Zeile den Tooltip-Text (der natürlich unterschiedlich sein kann) haben.---------
Hab auch gemerkt, dass es keinen Unterschied gibt, wenn das Control horizontal scrollt (außer ich hab das Problem nicht verstanden).@Martin:
Das, was du gesagt hast, mache ich ja, weiß eben nur nicht, wie ich es löse, damit ich für jede Zeile den Tooltip habe, aber trotzdem die neuesten Daten in der 1.Zeile der List einfüge.Hoffentlich kann man verstehen, was ich hier zum Ausdruck bringen will !?
-
Die Map ist einfach der falsche Ansatz. Wenn Du die Tooltips jeweils beim Einfügen in die Liste an Position 0 initialisierst, dann kann die Map logischerweise immer nur zwei Einträge enthalten. Alle zuvor gesetzten Einträge werden immer überschrieben, da die Formatierung für den Key immer nur 13 und 14 ergibt.
Mit jedem Einfügevorgang- und Sortiervorgang stimmt die Map nicht mehr mit den Einträgen in der Liste überein, da sich die Indizes der Einträge in der Liste ändern - die in der Map aber nicht.
Das einfachste ist die Verwendung von LVITEM.lparam. Damit kannst Du für jeden Listeneintrag einen benutzerdefinierten Eintrag setzen (z.B. Struktur mit den Tooltips für Spalte 13/14). Beim Entfernen des Eintrags muss die Struktur aber wieder gelöscht werden, das kann dann normalerweise bei LVN_DELETEITEM erfolgen.
-
Hi,
ja genau, das hab ich bis jetzt versucht auszudrücken, was teilweise etwas misslungen ist.

Klar ist es logisch, dass die Einträge immer wieder überschrieben werden, wenn ich immer wieder 0 angebe.
Ich hab bis jetzt bloß keinen anderen Ansatz gefunden.
Aber ich danke dir, werde das Genannte jetzt mal umsetzen.
Bei Problemen meld ich mich wieder.
-
Naja also so richtig nen Plan hab ich noch nicht, wie ich das jetzt umsetze.
Ok, ich hab ein struct mit den beiden Strings. Diesen struct erhält LVITEM als lparam.
Aber wie gehts jetzt am besten weiter ?
Kann heut nicht nachdenken!

-
Dann geh mal vor's Haus und eine Runde durch die Natur. Das hilft.

Kleiner Denkanstoß:
const CString& CMyListCtrl::GetToolTipText(UINT nItem, UINT nSubItem) { TOOLTIPINFO* pToolTipInfo = reinterpret_cast<TOOLTIPINFO*>(GetItemData(nItem)); if (NULL == pToolTipInfo) return _T(""); return (13 == nSubItem) ? pToolTipInfo->str13 : pToolTipInfo->str14; }PS: Nur so dahingetippt und nicht durch den Compiler gejagt.
Und nicht vergessen, TOOLTIPINFO vor dem beim Hinzufügen in LVITEM.lParam dynamisch anzulegen.
-
sri schrieb:
Dann geh mal vor's Haus und eine Runde durch die Natur. Das hilft.

Da hast du wohl recht, bin aber schon seit heut früh etwas verwirrt !

Egal, also ich hab im View meine Funktion, in der mein ListCtrl fülle. Darin setze ich auch den Text der beiden Tooltips zusammen und übergebe den dem struct, in dem dann am Ende 2 verschiedene CStrings enthalten sind.
Dann erhält lvItem.lParam die Adresse des structs mit den beiden Tooltip-Texten.
Und dann müsste ich mir noch überlegen, wie ich über SetTooltipText dann für jede Zeile die LVITEM-Struktur "speichere".Und das mit dem dynamischen Anlegen versteh ich noch nicht.

Man muss mir normalerweise nicht alles so aus der Nase ziehen !
Ich danke dir schonmal für die Geduld mit mir heute !!!
-
1. Struktur
typedef struct tagTOOLTIPINFO { CString str13; CString str14; } TOOLTIPINFO, *LPTOOLTIPINFO;2. Beim Einfügen in die Liste:
LVITEM lvItem; ... lvItem initialisieren lvItem.lParam = reinterpret_cast<LPARAM>(new TOOLTIPINFO);3. Tooltips setzen (SetTooltipText)
LPTOOLTIPINFO pToolTipInfo = reinterpret_cast<LPTOOLTIPINFO>(GetItemData(nItem)); pToolTipInfo->str13 = ...; pToolTipInfo->str14 = ...;4. Struktur beim Entfernen löschen
void CMyListCtrl::OnLvnDeleteItem(__in LPNMHDR pNMHDR, __out LRESULT* pResult) { LPNMLISTVIEW pNMListView = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); delete reinterpret_cast<LPTOOLTIPINFO>(pNMListView->lParam); }
-
Ok, war wohl etwas langsam, wollte gerade mein jetzige Lösung posten, die so ähnlich aussieht.

Bis auf das Entfernen der struct hab ich das so !
Hätte noch die Frage zum dynamischen Erzeugen gehabt, aber das hat sich ja jetzt erledigt.
Vielen Dank für deine Hilfe und Geduld !!

-
Hi,
habe acuh gerade so dieses Problem, will auch in bestimmten Spalten Tooltips anzeigen und bin auf diesen Fred gestoßen.
Habe ein paar Fragen dazu:
- bei diesem SetToolTipText verstehe ich nicht ganz, wieso da GetItemData verwendet wird !?
- muss dann aber auch beim Setzen SetItemData aufrufen und da was übergeben ?
- habe meine struct in einer anderen Klasse, weiß nicht wie die in einer anderen Klasse dynamisch erzeugen kann !?Verstehe das alles noch nicht so wirklich, vielleicht kann mich jemand aufklären !
-
Also ich kam jetzt erst wieder dazu, meine Lösung (was doch noch keine ist
)in Ruhe anzuschauen und mir ist noch etwas aufgefallen.m_strData.Format("Tip Nr.1"); CToolTip::tagTOOLTIPINFO *tool = new CToolTip::tagTOOLTIPINFO; tool->str1 = m_strData; m_strData.Format("Tip Nr.2"); tool->strFlags = m_strData; lvItem.lParam = reinterpret_cast<LPARAM>(tool); delete tool; tool = 0;Aber wieso ist beim Holen des Tooltips:
LPTOOLTIPINFO pToolTipInfo = reinterpret_cast<LPTOOLTIPINFO>(GetItemData(nItem)); if (nSubItem != 12 || nSubItem != 13 || pToolTipInfo == NULL) return ""; return (nSubItem == 12) ? pToolTipInfo->strTxtNr : pToolTipInfo->strFlags;pToolTipInfo immer 0 ?
Der lParam wird ja gesetzt, über SetItemData ist es das gleiche (einmal probiert)!
SetTooltipText brauch ich ja eig. nicht mehr, da ich dass ja alles gleich beim Erzeugen des Tooltip-Textes selber mache (das in den 1. Code-Tags).
EDIT:
Falls von Interesse:
ich füge so die Items und pro Zeile ein:VITEM lvItem; lvItem.mask = LVIF_TEXT; lvItem.pszText = ""; for (int i = 0; i < m_tool.GetHeaderCtrl()->GetItemCount(); i++) { lvItem.iItem = 0; lvItem.iSubItem = i; m_tool.InsertItem(&lvItem); }und jedes Item erhält den Text dann per SetItemText !
Das alles mit InsertItem, SetItemText, Tooltip-Text setzen... geschieht alles in einer Funktion.
-
delete tool; tool = 0;Das ist suboptimal. 'tool' darf erst gelöscht werden, wenn auch der Eintrag gelöscht wird (normalerweise in LVN_DELETEITEM).
Ansonsten musst Du beim Hinzufügen in LVITEM.mask auch LVIF_PARAM setzen, das hast Du vermutlich vergessen.
-
Sry fürs so späte melden.

Nochmals danke für deine Antwort !!
Ok, hab mir das schon gedacht, aber lieber ein delete zuviel als zu wenig.
Also kann ich den Pointer auf den struct als Member anlegen, leg den dann einmal pro Programmstart per new an und dann beim Beenden der Applikation wirds per delete entsorgt.
Setze also in meiner Funktion immer nur die beiden Strings neu und übergebe das dann lvItem.lParam !
Und das Flag LVIF_PARAM hatte ich auch noch nicht !SetTooltipText brauch ich ja eigentlich auch nicht, wenn ich schon den lParam setze ??
-
Ich hätte nicht gedacht, dass das hier so komplex wird.
Kann das Projekt jetzt weitermachen, aber beim Holen des Textes für den Tooltip (GetToolTipText) ist pToolTipInfo immer noch 0:const CString CToolTip::GetToolTipText(UINT nItem, UINT nSubItem) { if (nItem < 0 || nItem > 60) return ""; ToolTipText *pToolTipInfo = reinterpret_cast<ToolTipText*>(GetItemData(nItem)); if (!pToolTipInfo) return ""; if (nSubItem != 12 || nSubItem != 13 || pToolTipInfo == NULL) return ""; return (nSubItem == 12) ? pToolTipInfo->strTxtNr : pToolTipInfo->strFlags; }Und das Füllen des Controls sieht so aus:
void C...View::FillListCtrl() { LVITEM lvItem; lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.pszText = ""; for (int i = 0; i < m_tool.GetHeaderCtrl()->GetItemCount(); i++) { lvItem.iItem = 0; lvItem.iSubItem = i; m_tool.InsertItem(&lvItem); } ... ToolText *pText = new ToolText; m_strData.Format("Text Nr. %i", cnt); pText->strTxtNr = m_strData; m_strData.Format("Text Nr. %i", cnt); pText->strFlags = m_strData; lvItem.lParam = reinterpret_cast<LPARAM>(pText); ... }Mal davon abgesehen, dass ich in FillListCtrl durch das dauernde Anfordern Mem-Leaks kriege (was hier auch nur zum Test ist), kann ich es einfach nicht verstehen, wieso bei GetToolTipText pToolTipInfo immer 0 ist !
Und bei
void CToolTip::OnLvnDeleteitem(NMHDR *pNMHDR, LRESULT *pResult) { LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); delete reinterpret_cast<ToolTipText*>(pNMLV->lParam); *pResult = 0; }kriege ich ne Exception, weil lParam ungültig ist.
Aber das Setzen des lParams in FillListCtrl ist erfolgreich !Irgendwas überseh ich hier, aber was ?
-
Ist m_Tool die Listenansicht? InsertItem sollte nur einmal pro Eintrag aufgerufen werden (also pro Zeile) und nicht für jede Spalte.
Zudem musst Du lvItem.lParam natürlich auch vor dem entsprechenden InsertItem initialisieren und setzen. Im Nachhinein geht es nur über ein SetItemData.
-
Habe es grad mit SetItemData probiert (was eig auch nix anderes tut) und da funktioniert es.
So ist es, m_tool ist eine Instanz von der Klasse CToolTip, die public von CListCtrl erbt.
Ja, das stimmt natürlich, dass ich erst den lParam setzen muss, bevor ich InsertItem aufrufe!
War irgendwie klar, dass es eine einfache Sache war.Fakt ist: jetzt funktioniert es endlich !!

Ich danke dir vielmals für deine super, hilfreiche und dauernd verfügbare Hilfe !

Noch nen schönen Tag.