I created a custom CCustomCombo by extending CComboBox to implement a DrawItem() function. Here's the code for it.
void CCustomCombo::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
ASSERT( lpDrawItemStruct->CtlType == ODT_COMBOBOX );
LPCTSTR lpszText = ( LPCTSTR ) lpDrawItemStruct->itemData;
ASSERT( lpszText != NULL );
if ( lpDrawItemStruct->itemID == -1 || lpszText == NULL)
return;
CDC dc;
dc.Attach( lpDrawItemStruct->hDC );
// Save these value to restore them when done drawing.
COLORREF crOldTextColor = dc.GetTextColor();
COLORREF crOldBkColor = dc.GetBkColor();
// If this item is selected, set the background color
// and the text color to appropriate values. Erase
// the rect by filling it with the background color.
if ( ( lpDrawItemStruct->itemAction & ODA_SELECT ) &&
( lpDrawItemStruct->itemState & ODS_SELECTED ) )
{
dc.SetTextColor( ::GetSysColor( COLOR_HIGHLIGHTTEXT ) );
dc.SetBkColor( ::GetSysColor( COLOR_HIGHLIGHT ) );
dc.FillSolidRect( &lpDrawItemStruct->rcItem, ::GetSysColor( COLOR_HIGHLIGHT ) );
}
else
{
dc.FillSolidRect( &lpDrawItemStruct->rcItem, crOldBkColor );
}
// Draw the text.
dc.DrawText(
lpszText,
( int ) _tcslen( lpszText ),
&lpDrawItemStruct->rcItem,
DT_CENTER | DT_SINGLELINE | DT_VCENTER );
// Reset the background color and the text color back to their
// original values.
dc.SetTextColor( crOldTextColor );
dc.SetBkColor( crOldBkColor );
dc.Detach();
}
creation part -
m_selectionCombo.Create( WS_VSCROLL |
CBS_DROPDOWNLIST | WS_VISIBLE | WS_TABSTOP| CBS_OWNERDRAWFIXED,
rect, &m_wndSelectionBar, ID_TEMP_BTN))
Now the problem is with the adding string items to the combobox. When I'm using string objects, it always shows some unicode gibberish.
m_selectionCombo.InsertString(0, "One"); //works
char * one = "one";
m_selectionCombo.InsertString(0, one ); //works
CString one = "one";
m_selectionCombo.InsertString(0, one ); //shows gibberish
std::string one = "one";
char *cstr = &one[0];
m_wndSelectionBar.m_selectionCombo.InsertString(0, cstr ); //shows gibberish
The same results appear for AddString. The problem is that I have a set of doubles that I have to insert to the combobox. And I have no way of converting them to string without displaying gibberish. I tried half-a-dozen conversion methods and none worked. I'm literally at my wits end!
The funny thing is it worked perfectly before when I used CComboBox and not my CCustomCombo class/CBS_OWNERDRAWFIXED. I tried using CBS_HASSTRINGS, but it displayed nothing, not even the gibberish, so somehow the strings don't even get added in with CBS_HASSTRINGS.
I need the custom Draw method since I plan to highlight some of the dropdown items. I'm using windows 32, VS 2017.
Any help would be highly appreciated.
Thanks.
LPCTSTR lpszText = (LPCTSTR)lpDrawItemStruct->itemData;
OwnerDraw function is looking at itemData. itemData is assigned using CComboBox::SetItemData. It is not assigned using InsertString or other text functions.
char * one = "one";
m_selectionCombo.InsertString(0, one ); //works
The string and item data are stored in the same memory address when CBS_HASSTRINGS is not set.
See also documentation for CB_SETITEMDATA
If the specified item is in an owner-drawn combo box created without
the CBS_HASSTRINGS style, this message replaces the value in the
lParam parameter of the CB_ADDSTRING or CB_INSERTSTRING message that
added the item to the combo box.
So basically itemData returns a pointer one, and it works fine in this case.
CString one = "one";
m_selectionCombo.InsertString(0, one ); //shows gibberish
This time the string is created on stack, it is destroyed after the function exists. itemData points to invalid address.
Solution:
If you are setting the text using InsertString/AddString then make sure CBS_HASSTRINGS is set. And read the strings using GetLBText. Example:
//LPCTSTR lpszText = (LPCTSTR)lpDrawItemStruct->itemData; <- remove this
if(lpDrawItemStruct->itemID >= GetCount())
return;
CString str;
GetLBText(lpDrawItemStruct->itemID, str);
LPCTSTR lpszText = str;
Otherwise use SetItemData to setup data, and use itemData to read.
Related
I'm going to make a search function in mfc virtual list control
However, even if i change the search method, always output only the 0th row I don't know what the problem is.
i searched 0th column value
void CListControlDlg::OnBnClickedButton2()
{
CListCtrl* ListCtrl = ((CListCtrl*)GetDlgItem(IDC_LIST1));
CString aaaa;
aaaa.Format("%d", 56);
LVFINDINFO f1;
f1.flags = LVFI_STRING;
f1.psz = aaaa;
f1.vkDirection = VK_DOWN;
int num = ListCtrl->FindItem(&f1, -1);
if (num == -1) {
MessageBox(_T("검색 실패"), MB_OK);
return;
}
ListCtrl->SetItemState(
num,
LVIS_FOCUSED | LVIS_SELECTED,
LVIS_FOCUSED | LVIS_SELECTED
);
ListCtrl->EnsureVisible(num, true);
ListCtrl->SetFocus();
}
if i click button focus always on zero row
i am trying to set maximum length in string value and put '..' instead of removed chrs like following
String myValue = 'Welcome'
now i need the maximum length is 4 so output like following
'welc..'
how can i handle this ? thanks
The short and incorrect version is:
String abbrevBad(String input, int maxlength) {
if (input.length <= maxLength) return input;
return input.substring(0, maxLength - 2) + "..";
}
(Using .. is not the typographical way to mark an elision. That takes ..., the "ellipsis" symbol.)
A more internationally aware version would count grapheme clusters instead of code units, so it handles complex characters and emojis as a single character, and doesn't break in the middle of one. Might also use the proper ellipsis character.
String abbreviate(String input, int maxLength) {
var it = input.characters.iterator;
for (var i = 0; i <= maxLength; i++) {
if (!it.expandNext()) return input;
}
it.dropLast(2);
return "${it.current}\u2026";
}
That also works for characters which are not single code units:
void main() {
print(abbreviate("argelbargle", 7)); // argelb…
print(abbreviate("🇩🇰🇩🇰🇩🇰🇩🇰🇩🇰", 4)); // 🇩🇰🇩🇰🇩🇰…
}
(If you want to use ... instead of …, just change .dropLast(2) to .dropLast(4) and "…" to "...".)
You need to use RichText and you need to specify the overflow type, just like this:
Flexible(
child: RichText("Very, very, very looong text",
overflow: TextOverflow.ellipsis,
),
);
If the Text widget overflows, some points (...) will appears.
I need to show MessageBox with regional characters described in ISO/IEC 8859-13 codepage without setting Windows locale to this region. I was naive and tried to show ASCI table with one byte character:
void showCodePage()
{
char *a = new char[10000];
char *aa = new char[10000];
int f=0;
int lines =0;
for (int i=1; i<255;i++ )
{
sprintf(a,"%c %0.3d ",i,i);
sprintf(aa,"%c",i);
f++;
a+=6;
aa++;
if (f==8)
{
f=0;
sprintf(a,"%c",0x0d);
a++;
lines++;
}
}
*aa=0;
*a=0;
a-=254*6+lines;
aa-=254;
MessageBox(NULL, aa , "Hello!", MB_ICONEXCLAMATION | MB_OK);
MessageBox(NULL, a , "Hello!", MB_ICONEXCLAMATION | MB_OK);
delete [] a;
delete [] aa;
}
Ok, this doesn't shows ISO/IEC 8859-13 correctly and this is not possible without changing locale:
Now I decide to make unicode wstring. Converting from single byte char to unicode wchar function:
wstring convert( const std::string& as )
{
// deal with trivial case of empty string
if( as.empty() ) return std::wstring();
// determine required length of new string
size_t reqLength = ::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), 0, 0 );
// construct new string of required length
std::wstring ret( reqLength, L'\0' );
// convert old string to new string
::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), &ret[0], (int)ret.length() );
// return new string ( compiler should optimize this away )
return ret;
}
And changing MessageBox'es:
MessageBoxW(NULL, convert(aa).c_str(), L"Hello!", MB_ICONEXCLAMATION | MB_OK);
MessageBoxW(NULL, convert(a).c_str() , L"Hello!", MB_ICONEXCLAMATION | MB_OK);
Result is still sad:
In other hand what I was expecting? I need somehow tell system which code page it should use to display may characters. How to do that?
The problem with your solution is that the function MultiByteToWideChar with CodePage parameter CP_UTF8 deosn't translate your SPECIFIC ASCII code-page to UTF-16, it translates UTF-8 to UTF-16, which is not what you need.
What you're looking for is a translation table from chars in ISO/IEC 8859-13 to WideChar. You can manually make one from the table in https://en.wikipedia.org/wiki/ISO/IEC_8859-13, e.g. 160 becomes 00A0, 161 to 201D, and so on.
I am trying to add items from alistbox to cstringarray. But text is null always. plz suggest the changes
int count = m_OutList.GetCount();
for ( i = 0; i <m_OutList.GetCount(); i++)
{
m_OutList.GetText( buf[i], text );
m_selcomponents->Add(text);
// getb //Add();
}
If text is a CString in your example, you need to write m_OutList.GetText(i,text) - you don't need a buffer variable if you pass a CString&. buf[i] is a part of your buffer and has a random value.
How to copy a folder from one drive to other drive in VC++ ...?
I have come this far
String^ SourcePath = Directory::GetCurrentDirectory();
String^ DestinationPath = "c:\\Test";
CString s(SourcePath) ;
CString d(DestinationPath);
Directory::CreateDirectory(DestinationPath);
SHFILEOPSTRUCT* pFileStruct = new SHFILEOPSTRUCT;
ZeroMemory(pFileStruct, sizeof(SHFILEOPSTRUCT));
pFileStruct->hwnd = NULL;
pFileStruct->wFunc = FO_COPY;
pFileStruct->pFrom = (LPCWSTR)s;//"D:\test_documents\test1.doc";
pFileStruct->pTo = (LPCWSTR)d;
pFileStruct->fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR ;
bool i = pFileStruct->fAnyOperationsAborted ;
int status = SHFileOperation(pFileStruct);
if(status == 0)
{
return true;
}
return false;
the status is showing 2 instead of zero , can some one tell me why..?
Usually a String^ points to a managed string object. The SHFILOPSSTRUCT must befilled with pointers to unmanaged wchar_t. So you must pin the strings and convert. You tried to use the CString class as conversion helper.
Use the PtrToStringChars instead to get valid strings in pTo and pFrom:
http://msdn.microsoft.com/en-us/library/d1ae6tz5(VS.80).aspx
The read of the fAnyOperationsAborted member is not required for the operation.