| ||||||||||||||||
![]() | ||||||||||||||||
| ||||||||||||||||
![]() | ||||||||||||||||
| ||||||||||||||||
![]() |
MS Visual C++ / MFC FAQ Вопросы
Ответы Q1. Как показать ProgressBar на StatusBar'е ? A1. Предположим, что вы хотите показать CProgressCtrl на весь StatusBar.
Для этого необходимо проделать следующее: static UINT indicators[] = { ID_PROGRBAR }; - В файле _MainFrm.h создайте protected переменную m_bCreated типа
BOOL и public переменную m_progress типа CProgressCtl. к участку кода: if (!m_wndStatusBar.Create(this ) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof (UINT))) { TRACE0("Failed to create status bar\n" ); return -1; // fail to create } добавьте следующую строку: else { m_wndStatusBar.SetPaneInfo(0,ID_PROGRBAR,SBPS_STRETCH,10); } Кроме того, добавьте инициализацию нашей переменной m_bCreated ......... m_bCreated=FALSE; .......... - Теперь мы можем использовать ProgressBar в строке статуса, естественно не
забыв создать этот объект. Предположим, у нас есть функция
CMainFrame::OnWork(). Она будет выглядеть примерно так: void CMainFrame::OnWork() { RECT rc; m_wndStatusBar.GetItemRect(0,&rc); if (m_bCreated==FALSE) { // создаем m_progress m_progress.Create(WS_VISIBLE|WS_CHILD, rc,&m_wndStatusBar, 1); // Устанавливаем размер от 0 до 100 m_progress.SetRange(0,100); m_progress.SetStep(1); m_bCreated=TRUE; } for (int I = 0; I < 100; I++) { Sleep(20); m_progress.StepIt(); } } -Если откомпилировать проект на этой фазе, то все будет работать, но при
изменении размера окна линейка ProgressBar'а размеры менять не будет, поэтому
необходимо перекрыть событие OnSize: void CMainFrame::OnSize(UINT nType, int cx, int cy) { CFrameWnd::OnSize(nType, cx, cy); if (m_bCreated) { RECT rc; m_wndStatusBar.GetItemRect(0,&rc); m_progress.SetWindowPos(&wndTop, rc.left, rc.top, rc.right - rc.left,rc.bottom - rc.top, 0); } } - Вот теперь все /-))))) Откомпилируйте проект и убедитесь, что все работает. Q2. Как использовать CTreeCtrl для построения дерева каталогов диска, как в Проводнике ? Неужели необходимо рекурсивно просмотреть диск, а потом прописать ручками все Итемы данного контрола ?? A2. (A. Лисеев Дмитрий. Это тормозно и глючно. На больших дисках это займет несколько минут. Если
каталоги добавляются или удалются другими приложениями во время работы твоего
контрола, то будешь весь в проблемах. Все гораздо проще. Никаких рекурсий.
Просматриваем корневой каталог на предмет наличия подкаталогов и создаем итемы
первого уровня, в которых создаем по одному фиктивному итему (чтобы крестик
был и итем можно было раскрыть). Как только юзер пытается раскрыть итем, соответствующий некому каталогу, мы
удаляем из него фиктивный итем, просматриваем этот подкаталог и добавляем
соответствующие итемы со своими фиктивными внутри. Как только юзер закрывает итем, мы удаляем из него все дочерние итемы и обратно добавляем фиктивный. Если структура каталогов изменилась, для обновления юзеру достаточно просто закрыть и открыть соответствующую ветку. Именно так и работает "Проводник". Q3. Есть класс - потомок CListView. Как изменить стиль у объекта CListCtrl, принадлежащего к этому *view (например установить стиль Report) ? A3. Для этого пишите в OnInitialUpdate вашего вида void CMyListView::OnInitialUpdate() { ...... CListView::OnInitialUpdate(); CListCtrl& theCtrl = GetListCtrl(); DWORD dwStyle=GetWindowLong(theCtrl.m_hWnd,GWL_STYLE); SetWindowLong(theCtrl.m_hWnd,GWL_STYLE,dwStyle|LVS_REPORT); ....A3. (by Pavel Nazin 2:5020/1053.21) Гораздо проще перекрыть PreCreateWindow (лучше всего воспользоваться
ClassWizard-ом) и поковырять переданный по ссылке CREATESTRUCT типа такого: BOOL CMyListView::PreCreateWindow(CREATESTRUCT& cs) { cs.style|=LVS_REPORT;//так мы добавляем стиль cs.style&=LVS_REPORT;//а вот так снимаем return CMyListView::PreCreateWindow(cs); } Q4. Как CString привести к char * ? _ A4. (by Yuri Khodin 2:5020/1200.20) #include <atlbase.h> USES_CONVERSION; CString strData(_T("Some Data")); char* lpszString = T2A((LPTSTR)(LPCTSTR)strData);A4. (by Paul Kalyakin 2:5029/3.29 CString tmp_str; char* st; st=tmp_str.GetBuffer(tmp_str.GetLength()) важно то, что если с tmp_str что-либо сделать, то необходимо опять получить указатель на внутренний буфер CString. Q5. Какие библиотеки Freeware/Commercial существуют для Visual C++ ? _ A5. 1- BCG Control Library (freeware) Stringray Software (commercial) www.stingray.com
Фирма Stringray Software производит библиотеки для Visual C++ (MFC, ATL): кроме этих, есть и другие продукты Q6.А можно пример консольной программы ? _ A6. by Alexander Fedorov (2:5030/437.74) #include <windows.h> #include <stdlib.h> void main() { HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); SMALL_RECT srct; CHAR_INFO chiBuffer[160]; COORD coord1, coord2; char ddd[666]; CharToOem("2:5095/38 - злобный ламерюга", ddd); DWORD cWritten; coord1.Y = 0; coord1.X = 0; hStdout = GetStdHandle(STD_OUTPUT_HANDLE); WriteConsoleOutputCharacter(hStdout, ddd, lstrlen(ddd), coord1, cWritten); for (int i = 0; i { WORD wColors = 1 + i * 3; coord1.X = i; WriteConsoleOutputAttribute(hStdout, , 1, coord1, cWritten); } srct.Top = 0; srct.Left = 0; srct.Bottom = 1; srct.Right = 79; coord1.Y = 0; coord1.X = 0; coord2.Y = 1; coord2.X = 80; ReadConsoleOutput(hStdout, chiBuffer, coord2, coord1, ); for (i = 0; i { srct.Left = (SHORT)((double)(79 - lstrlen(ddd)) * rand() / RAND_MAX); srct.Top = (SHORT)((double)25 * rand() / RAND_MAX); srct.Bottom = srct.Top + 1; WriteConsoleOutput(hStdout, chiBuffer, coord2, coord1, ); } Sleep(10000); Q7. В созданном мастером (VC 6.0 ) win32 Console Application попытка вывести русский текст дает кракозяблики.Что делать ? _ A7. by Dmitriy Reznitskiy (2:5020/1452.112) CharToOem, OemToChar - оно? Q8. Пытаюсь из своей программы вызвать Word97, для это делаю несколько импортов и в результате имею кучу ошибок. Как правильно ? _ A8. by Igor Tkachoff (2:5037/9.37) // Office.h #define Uses_MSO2000_ #ifdef Uses_MSO2000 // for Office 2000 #import <mso9.dll> #import <vbe6ext.olb> #import <msword9.olb> rename("ExitWindows","_ExitWindows") #import <excel9.olb> rename("DialogBox","_DialogBox") \ rename("RGB","_RGB") \ exclude("IFont","IPicture") #import <dao360.dll> rename("EOF","EndOfFile") rename("BOF","BegOfFile") #import <msacc9.olb> #else // for Office 97 #import <mso97.dll> #import <vbeext1.olb> #import <msword8.olb> rename("ExitWindows","_ExitWindows") #import <excel8.olb> rename("DialogBox","_DialogBox") \ rename("RGB","_RGB") \ exclude("IFont","IPicture") #import <DAO350.DLL> \ rename("EOF","EndOfFile") rename("BOF","BegOfFile") #import <msacc8.olb> #endif<>pКаталоги проставь сам, если надо. Просто я предпочитаю сваливать все библиотеки в одну кучу. А еще лучше сделать #import один раз, а затем подключать #include "тыры-пыры.tlh". P.S. С 2000'ным аккуратнее. Некоторые методы (типа Run, Open, Add) имеют новую версию. И если хочешь совместимость с 97 то следует вызывать старые версии, которые называются типа RunOld и т.п. Q9. А как отредактировать ресурсы .exe файла ? _ A9. Это возможно лишь под NT. Q10. Как программно получить номер билда своего приложения в VC++? _ A10. by Pavel Zolotuhin (2:5025/60.15) Штатной возможности нет, поскольку не все одинаково трактуют понятие "номер билда" и не все одинаково его используют. Однако большинство людей используют для хранения номера билда конкретного файла ресурсы типа VERSIONINFO, откуда эту информацию можно потом получить (для отображения в диалоге "О программе" :-) с помощью функций из version.dll. Упрощенно говоря, информация о версии файла хранится в VERSIONINFO в виде четырех чисел, значимость которых убывает слева направо. Например, для mfc42.dll из поставки Win2k версия файла выглядит как 6.0.8665.0. Здесь первая цифра, как я понимаю, совпадает с версией продукта (MSVC 6), вторая означает подверсию (MSVC 6.0), третья - номер билда, а четвертая - я не знаю. В своих dll-ках и exe-шниках Microsoft постоянно использует эту схему, я - тоже. Обычно для автоматического увеличения номера версии используются макросы Visual Studio (== скрипты на VBScript), ковыряющие файл ресурсов проекта. Эти макросы либо связываются с кнопкой на тулбаре MSDev, либо вызываются из обработчика события Application_BeforeBuildStart в файле макросов. Примеры подобных макросов горой лежат на девелоперских сайтах, наподобие www.codeguru.com. Для себя я сделал собственный, который реализует номер билда в указанном выше смысле. Вот его исходник (должен работать на MSVC6SP3). Sub IncVersion() 'DESCRIPTION: Increments file version Dim oDoc Dim iVer Set oDoc = Documents.Open(Application.ActiveProject &".rc", "Text") if oDoc Is Nothing Then Exit Sub End If oDoc.Selection.FindText "FILEVERSION", dsMatchCase if Len(oDoc.Selection) = 0 Then oDoc.Close dsSaveChangesNo Set oDoc = Nothing Exit Sub End If oDoc.Selection.EndOfLine oDoc.Selection.FindText ",", dsMatchBackward oDoc.Selection.CharLeft oDoc.Selection.WordLeft dsExtend iVer = oDoc.Selection iVer = iVer + 1 oDoc.Selection = iVer oDoc.Selection.FindText """FileVersion""", dsMatchCase if Len(oDoc.Selection) = 0 Then oDoc.Close dsSaveChangesNo Set oDoc = Nothing Exit Sub End If oDoc.Selection.EndOfLine oDoc.Selection.FindText ",", dsMatchBackward oDoc.Selection.CharLeft oDoc.Selection.WordLeft dsExtend iVer = oDoc.Selection iVer = iVer + 1 oDoc.Selection = iVer oDoc.Close dsSaveChangesYes Set oDoc = Nothing End Sub Q11. Какой функцией можно переключить видеорежим ? A11. by Alexander Shargin (2:5030/852.22) Этим занимается ChangeDisplaySettings(...); Вот тебе пример, который устанавливает разрешение 640x480 (24 bit): === Cut === DEVMODE md; ZeroMemory(&md, sizeof(md)); md.dmSize = sizeof(md); md.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; md.dmBitsPerPel = 24; md.dmPelsWidth = 640; md.dmPelsHeight = 480; ChangeDisplaySettings(&md, 0); === Cut === Только не повторяй ошибку, которую допустил я, когда писал этот пример: восстанови исходное разрешение, когда твоя программа будет заканчивать выполнение. Q12. Как вызвать окно выбора папки ? A12. Воспользуйтесь следующей функцией: BOOL FGetDirectory(LPTSTR szDir) { BOOL fRet; TCHAR szPath[MAX_PATH]; LPITEMIDLIST pidl; LPITEMIDLIST pidlRoot; LPMALLOC lpMalloc; BROWSEINFO bi = { NULL, NULL, szPath, "Выберите папку", BIF_RETURNONLYFSDIRS, NULL, 0L, 0 }; if (0 != SHGetSpecialFolderLocation(HWND_DESKTOP, CSIDL_DRIVES, &pidlRoot)) return FALSE; if (NULL == pidlRoot) return FALSE; bi.pidlRoot = pidlRoot; pidl = SHBrowseForFolder(&bi); if (NULL != pidl) fRet = SHGetPathFromIDList(pidl, szDir); else fRet = FALSE; // Get the shell's allocator to free PIDLs if (!SHGetMalloc(&lpMalloc) && (NULL != lpMalloc)) { if (NULL != pidlRoot) { lpMalloc->Free(pidlRoot); } if (NULL != pidl) { lpMalloc->Free(pidl); } lpMalloc->Release(); } return fRet; } LPTSTR PszAlloc(int cch) { return (LPTSTR) LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * (cch+1)); } bool PszDeAlloc(HLOCAL mem_ptr) { return (LocalFree(mem_ptr)==NULL) ? true : false; } Затем, при необходимости предложить пользователю выбрать папку
используйте примерно такой код: .... LPTSTR fname; fname=PszAlloc(250); FGetDirectory(fname); ...... PszDeAlloc((HLOCAL)fname); HomePage для этого FAQ - |
|
![]() | ||||||||||||||||
| ||||||||||||||||
![]() | ||||||||||||||||
|