Retrieving client area coordinates of a character position from text control
I am in need of writing a function which can get screen co开发者_StackOverflowordinates from the character position in a text edit control. I am using text edit control provided by wxWidgets
framework. The wxTextCtrl
is not exposing any API functions which can provide this information. On Windows, I can get the information by sending EM_POSFROMCHAR to the text control.
I am wondering how the same can be done on other environments like Linux. For now this needs to be done on only the desktop environments which runs on top of X Window System like GNOME, KDE and XFCE. Is there a way to do it? And on these DE, who draws the controls like text edit? Is it managed by X and styled by particular DE?
Any help would be appreciated.
Well, it is possible, but you need to implement a wxTextCtrl
derived control that relies on underlaying platform capabilities for any particular wxWidgets port (wxMSW, wxGTK, etc).
So, because you have asked about Linux implementation. Let me explain how to implement it for wxGTK 2.9. Below is the wxTextCtrlExt
control definition:
#include <wx/textctrl.h>
#include <wx/gdicmn.h>
//-----------------------------------------------------------------------------
// wxTextCtrlExt
//-----------------------------------------------------------------------------
class wxTextCtrlExt : public wxTextCtrl
{
public:
wxTextCtrlExt() : wxTextCtrl() { }
wxTextCtrlExt(wxWindow* parent,
wxWindowID id,
const wxString& value = wxEmptyString,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTE_MULTILINE,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxTextCtrlNameStr)
: wxTextCtrl(parent, id, value, pos, size, style, validator, name ) { }
wxPoint GetPositionCoords(long pos);
};
And the wxGTK implementation:
#include "wxTextCtrlExt.h"
#include <wx/defs.h>
#include <gtk/gtk.h>
wxPoint wxTextCtrlExt::GetPositionCoords(long pos)
{
if ( IsMultiLine() ) {
GtkTextView* txtView = GTK_TEXT_VIEW(m_focusWidget);
GtkTextBuffer* txtBuffer = gtk_text_view_get_buffer(txtView);
GtkTextIter iter;
gtk_text_buffer_get_iter_at_offset(txtBuffer, &iter, pos);
GdkRectangle location; // output location in buffer coordinates
gtk_text_view_get_iter_location(txtView, &iter, &location);
return wxPoint(location.x, location.y);
}
return wxPoint(0,0);
}
You may also want to convert your buffer coordinates to a widget's ones:
// If we need to convert our coordinates to
GdkPoint out;
gtk_text_view_buffer_to_window_coords(txtView, GTK_TEXT_WINDOW_WIDGET, location.x, location.y, &out.x, &out.y );
return wxPoint(out.x, out.y);
As you can see, this particular implementation does not account for a single line text entry, that's why you need to use a wxTE_MULTILINE
style when you are creating the wxTextCtrlExt
control.
Well, below is how to use it. Let's m_Text2
be the pointer to a child object of wxTextCtrlExt
class:
long iCharPos = m_Text2->GetInsertionPoint();
long iCharPosMax = m_Text2->GetLastPosition();
wxPoint pos = m_Text2->GetPositionCoords(iCharPos);
Now we got our character position coordinates in pos
. That's it!
Some links that maybe of any interest to you:
- GtkTextView — Widget that displays a GtkTextBuffer
- GtkTextBuffer — Stores attributed text for display in a GtkTextView
Now it is all about your second question.
And on these DE, who draws the controls like text edit? Is it managed by X and styled by particular DE?
This depends on the wxWidgets port you are using. The wxMSW and wxGTK ports use Win32 and GTK+2 native controls, respectively. The wxUniversal based ports (such as wxX11, wxMGL) draw all the controls by wxWidgets itself. X Window System does not mandate the user interface by itself. It provides the basic framework for building GUI environments: drawing and moving windows on the screen and interacting with a mouse and keyboard.
I'm not completely clear which character position is sought, but the solution will likely involve wxTextCtrl::XYToPosition()
and/or wxTextCtrl::PositionToXY()
, but it is unclear which coordinate system the result should be expressed in.
wxTextCtrl
inherits from wxWindow
which offers wxWindow::GetPosition()
. The parent is found by wxWindow::GetParent
.
Between the lot of them, I suspect the answer is easily derived.
It's been a while since my last wxWidgets experience, but if you can't find an easier (shorter) way, would calculating the extent of the text before the caret (e.g. using wxDC::GetTextExtent()) be a possible approach to finding the position you're after? This would give you a position relative to the start of the text in the wxTextCtrl. You may have to take border sizes and spacing between border and actual text into account. If necessary refine through wxTextCtrl::HitTest()?
BTW What about wxStyledTextCtrl?
Have you considered doing a binary search using the HitTest
function? Not very elegant, but it should be fast, and HitTest
is implemented for wxGTK2 so it should work.
精彩评论