问题描述
我正在创建一个 C++ wxWidgets 计算器应用程序。我有一个显示当前计算的 wxTextCtrl。它被设置为只读,因为我使用 wxKeyEvent 来写入它。问题是,虽然它被设置为只读,插入符号仍然显示:
我希望文本控件中的文本可以选择和不可编辑,没有插入符号。
有什么建议吗?
解决方法
以下示例说明了如何创建外观和行为应与您所描述的一样的只读样式文本控件。 wxStyledTextCtrl 有很多很多方法,因此可以根据需要进一步自定义外观和行为。
MainText = new wxStyledTextCtrl(<parent>,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxBORDER_NONE);
// Set a small minimimum size.
MainText->SetMinClientSize(wxSize(0,0));
// Set the default style to use the Lato bold font.
MainText->StyleSetFaceName(0,"Lato");
MainText->StyleSetBold(0,true);
// Set the control read only and set the caret invisible.
MainText->SetReadOnly(true);
MainText->SetCaretStyle(wxSTC_CARETSTYLE_INVISIBLE);
// Hode the horizontal scroll bar and the left margin.
MainText->SetUseHorizontalScrollBar(false);
MainText->SetMarginWidth(1,0);
// Use the newer D2D drawing.
MainText->SetTechnology(wxSTC_TECHNOLOGY_DIRECTWRITE);
我在研究这个答案时了解到有一个选项可以将插入符号设置为不可见,因此没有必要像我上面提到的那样将其设置为背景颜色。
要调整字体以填充大部分控件,您可以增加和减少缩放比例,直到文本大小足够。我认为这也应该解决您另一个问题中的尺寸问题。
MainText->Bind(wxEVT_SIZE,[this](wxSizeEvent& evt) {
evt.Skip();
int stcHt = evt.GetSize().GetHeight()/1.3;
int zoom = MainText->GetZoom();
if ( stcHt > MainText->TextHeight(0) )
{
// Increase the zoom until a line of text is taller than stcHt.
while ( stcHt > MainText->TextHeight(0) )
{
zoom = MainText->GetZoom();
MainText->SetZoom(zoom+1);
}
}
else
{
// Decrease the zoom until a line of text is shorter than stcHt.
while ( stcHt <= MainText->TextHeight(0) )
{
zoom = MainText->GetZoom();
MainText->SetZoom(zoom-1);
}
zoom = MainText->GetZoom();
}
MainText->SetZoom(zoom);
});
您说您正在更新文本以响应关键事件。要使用样式文本控件执行此操作,您需要将控件设置为非只读,进行更改,然后将其设置回只读。像这样:
MainText->SetReadOnly(false);
//update the text in response to the key event.
MainText->SetReadOnly(true);
您可以使用多种方法来更新文本。我认为最有可能有用的是 InsertText、AppendText 和 AddText。
如果您想尝试删除显示计算的文本和显示结果的文本之间的额外填充,有方法 SetExtraAscent
可以传递一个负数以删除每个文本字符上方的额外空格线。问题是输入是许多原始像素。但是 size 事件处理程序通过设置缩放来工作,因此每个缩放级别的像素数都会不同。
不过有一个解决方法。 MainText->TextHeight
返回的值基本上是我提到的指标上升、下降和内部领先的总和 here。为了去除每行顶部的额外填充,我们可以将 SetExtraAscent
设置为基本上是内部行距的负数。
执行此操作的计算有点棘手。首先,我们可以估计字体的高度有多少是由内部行距组成的。我能想到的最简单的方法是创建一个临时内存 dc 并获取如下指标:
// Create a temporary memory dc to do some font calculations.
wxMemoryDC mem;
wxFont font(wxFontInfo(wxSize(0,1000))
.Family(wxFONTFAMILY_SWISS)
.FaceName("Lato")
.Bold());
mem.SetFont(font);
wxFontMetrics metrics = mem.GetFontMetrics();
double internalLeadingPecent = static_cast<double>(metrics.internalLeading) /
static_cast<double>(metrics.height);
然后可以调整大小处理程序以尝试删除像这样的内部前导:
MainText->Bind(wxEVT_SIZE,[this,internalLeadingPecent](wxSizeEvent& evt) {
evt.Skip();
// First set the extra accent back to zero so that we get
MainText->SetExtraAscent(0);
int stcHt = evt.GetSize().GetHeight();
int zoom = MainText->GetZoom();
int internalLead = internalLeadingPecent*stcHt;
if ( stcHt > MainText->TextHeight(0) - internalLead )
{
// Increase the zoom until a line of text is taller than stcHt.
while ( stcHt > MainText->TextHeight(0) - internalLead)
{
zoom = MainText->GetZoom();
MainText->SetZoom(zoom+1);
}
}
else
{
// Decrease the zoom until a line of text is shorter than stcHt.
while ( stcHt <= MainText->TextHeight(0) - internalLead )
{
zoom = MainText->GetZoom();
MainText->SetZoom(zoom-1);
}
zoom = MainText->GetZoom();
}
MainText->SetExtraAscent(-1*internalLead);
MainText->SetZoom(zoom);
});
我的快速实验表明,这消除了样式文本控件与其上方窗口之间的大部分填充。如果您需要删除更多填充,您可以尝试进一步调整,例如删除 '-1.2*internalLead',如果这看起来效果更好的话。但这些调整只能通过试验找到。字体真的很难处理。