2010-11-23 7 views
3

Also ich ein benutzerdefiniertes Steuerelement in C# erstellen (nicht WPF), und ich möchte im Grunde Text Highlighting mit der Maus implementieren.Suchen Sie ein Zeichen in einer benutzerdefinierten Zeichenkette an einem bestimmten Punkt

Wie finde ich effizient das Zeichen an einem bestimmten Point (sagen Sie, wo die Maus angeklickt wird) in einer Zeichenfolge? Ich habe das Layoutrechteck der Zeichenkette, wie es gezeichnet wurde, und ich könnte die Länge der Zeichenkette bis zu jedem Zeichen berechnen, bis ich diejenige finde, die am nächsten ist, wo die Maus angeklickt wird ... aber es muss einen besseren Weg geben. Irgendwelche Vorschläge?

+0

Können Sie ein schreibgeschütztes 'TextBox'-Steuerelement nicht verwenden? Das wird die Arbeit für dich erledigen. –

+0

Beziehen Sie dieses Steuerelement von Textbox? – Scottie

+0

@Scottie - Nein, erbt nur von UserControl. RichTextBox und TextBox sind nicht ganz das, was ich brauche, und ich bin wirklich nur neugierig, wie ich meine eigenen guten benutzerdefinierten Steuerelemente erstellen kann. – climbage

Antwort

3

Wenn ich das tun müsste, würde ich es rückwärts betrachten.
Ich würde den Text als string Mitglied in der Steuerung eingegeben, so weiß ich jederzeit, was tatsächlich in das Steuerelement eingegeben wird (wie die Eigenschaft in einem TextBox).
Dann würde ich die TextRenderer.MeasureText() Methode verwenden (http://msdn.microsoft.com/en-us/library/7sy6awsb.aspx) und ich würde die Länge der Zeichenfolge wiederholt messen, bis ich die X-Koordinate der Maus übergeben innerhalb der Kontrolle, genau dann weiß ich, wie viele Zeichen gewählt werden.

Angenommen, der Benutzer hat den Text Hello in das Steuerelement geschrieben.
Und die X-Koordinate traf direkt zwischen dem l und dem o, die dann von Wert 20.
könnte ich immer wieder auf die folgenden Zeichenfolgen aufrufen würde MeasureText():

  • H: Breite von 5 Pixel.
  • He: Breite von 10 Pixel.
  • Hel: Breite von 14 Pixel.
  • Hell: Breite von 17 Pixel.
  • Hello: Breite von 22 Pixel.

Dann weiß ich die Maus zwischen den l und den o getroffen wurde, so würde ich dann markieren Sie den Text Hell.

Sorry für das geschmacklos Beispiel =)

UPDATE:
Sie können durch die Berechnung der Längen in einer binary-search-baumartigen Art und Weise dies ein wenig optimieren.
Genau wie Sie einen Namen im Telefonbuch nachschlagen würden, sehen Sie nicht Seite für Seite, sondern eher in zwei Hälften geteilt, je näher Sie kommen, bis es definitiv zwischen diesen beiden Seiten liegt.
In ähnlicher Weise, insbesondere für lange String-Werte des Steuerelements, berechnen Sie die Breite des gesamten Strings, dann die Hälfte seiner Länge, und teilen Sie es dort. Ich denke, das wäre an diesem Punkt O(n log n).
Natürlich wäre es O(1), wenn der Text mit fester Breite ist =)

+0

Ja, das ist ziemlich genau das, was ich jetzt mache. Ich muss diese Lösung vielleicht einfach behalten, wenn ich keinen effizienteren Weg finde. – climbage

+0

Oh, und der Text kann mehrere Zeilen umbrechen. – climbage

+0

@klimbage; das wäre eine kleine Herausforderung. Sie müssen zuerst die Y-Koordinate in den Index des Zeichens übersetzen, das diese Zeile startet, und dann folgen Sie derselben Logik oben. – BeemerGuy

2

Eine andere Sache, die Sie auf BeemerGuy den großen Vorschlag bauen tun können, ist ein Array von Offsets vorauszuberechnen. Wenn die Zeichenfolge geändert wird (die Benutzertypen oder die Eigenschaft wird im Code festgelegt), können Sie das Versatzfeld neu berechnen. Das spart Ihnen den Aufruf von MeasureFont bei den Mausklicks und macht das Finden des Zeichens trivial. Sie durchlaufen das Array im Grunde, bis Sie das nächste Zeichen finden.Da die Offsets implizit nach Wert sortiert sind, können Sie sogar eine binäre Suche verwenden, um sie effektiver zu machen.

+0

Ich mag das; Es ist eher wie Indexierung. Das ist ein guter Weg, um es zu optimieren, vor allem wenn es um Echtzeit-Interaktivität geht. schnelle Reaktionsfähigkeit ist dort zwingend erforderlich! – BeemerGuy

+0

Das einzige Problem dabei ist, dass sich das Wort "Wrapping" meines Textes jederzeit ändern kann, so dass sich die Versätze jedes Charakters ändern, es sei denn, Sie haben einen anderen Weg. – climbage

+0

@klimage; eigentlich wäre das ideal für Ihren Multi-Line-Fall; Sie erstellen die Offsets am Anfang jeder Zeile, dann übersetzen Sie einfach Y in die Zeilennummer des Arrays und kombinieren diese mit der Logik meiner Antwort. – BeemerGuy

Verwandte Themen