Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > работа с кареткой


Автор: yngwie19 19.4.2009, 17:38
Скажите как правильно использовать DestroyCaret() ? Когда вызываю эту функцию то GetLasError возвращает ("Отказано в доступе")

Автор: 586 19.4.2009, 20:00
Что возвращает DestroyCaret - TRUE или FALSE? Функция работает?
Вызывать GetLastError следует тогда, когда функция возвращает FALSE.

Автор: yngwie19 19.4.2009, 21:55
586, функция возвращает FALSE, может потаму что Я не вызвал функцию CreateCaret() ? поэтому не работает . ?

Автор: 586 19.4.2009, 22:25
Где эта функция вызывается и для чего?

Автор: yngwie19 19.4.2009, 22:33
586, CreateCaret() вызывать не нужно?
Ну вот посмотри ээто твой пример который ты мне давал в нем эта функция в обработке WM_CREATE:
Код

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <Richedit.h>

HWND hMainWnd = 0;
HWND hWndRichEdit = 0;
HWND CiipboardViewer = 0;


LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    case WM_SIZE:
        {
        MoveWindow(hWndRichEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);

        PARAFORMAT pf = {0};
        pf.cbSize = sizeof(pf);
        pf.dwMask = PFM_ALIGNMENT;
        pf.wAlignment = PFA_CENTER;

        // Выделить текст
        SendMessage(hWndRichEdit,EM_SETSEL,0,-1);
        
        // Применить к выделению центрирование
        SendMessage(hWndRichEdit,EM_SETPARAFORMAT,0,(LPARAM)&pf);
        
            SendMessage(hWndRichEdit, (WM_USER + 225), 6, 5);     
        break;
        }
    case WM_CREATE:
        DestroyCaret();
        break;
        
    case WM_CHANGECBCHAIN:
        break;

    case WM_DRAWCLIPBOARD:
        break;

    }
    
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc = {0};

    wc.cbSize = sizeof(wc);
    wc.lpfnWndProc = MainWndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
    wc.lpszClassName = _T("MainWndClass");
    RegisterClassEx(&wc);

    

    hMainWnd = CreateWindowEx(0, wc.lpszClassName, _T("TestApp"), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        200, 200, 400, 365, NULL, NULL, hInstance, NULL);

    // Очистка буфера обмена
    if (OpenClipboard(hMainWnd))
        EmptyClipboard();

    LoadLibrary("Msftedit.dll");

    hWndRichEdit = CreateWindowEx(0, _T("RichEdit50W"), NULL, WS_VISIBLE | WS_CHILD | WS_BORDER |
            ES_MULTILINE | WS_VSCROLL | WS_HSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_READONLY | ES_CENTER,
        0, 0, 380, 320, hMainWnd, NULL, hInstance, NULL);

    HANDLE hFile = CreateFile(_T("C:\\3.rtf"), GENERIC_READ, FILE_SHARE_READ,
        0, OPEN_EXISTING, 0, 0);
    if(hFile != INVALID_HANDLE_VALUE)
    {
        DWORD dwRead = 0, dwSize = GetFileSize(hFile, NULL);
        char *buf = new char[dwSize+1];
        ReadFile(hFile, buf, dwSize, &dwRead, 0);
        buf[dwRead] = '\0';
        CloseHandle(hFile);

        SetWindowTextW(hWndRichEdit, (wchar_t*)buf);   // передаётся ANSI строка. работает. тестировалось в WinXP SP2.
                // при портировании на другие версии ОС Windows может не работать.
     
      delete []buf;
    }


    MSG msg;
    while(GetMessage(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

Автор: 586 19.4.2009, 22:45
Цитата(yngwie19 @  19.4.2009,  23:33 Найти цитируемый пост)
    case WM_CREATE:
        DestroyCaret();

Это для того, чтобы скрыть каретку RichEdit'а? В момент вызова hMainWnd WM_CREATE, RichEdit ещё не создан. А вообще, для cкрытия кареток лучше использовать функцию HideCaret.

Автор: GremlinProg 19.4.2009, 22:57
Цитата(586 @  20.4.2009,  00:45 Найти цитируемый пост)
А вообще, для cкрытия кареток лучше использовать функцию HideCaret.

нет, 586, не пройдет
пара BeginPaint-EndPaint уже ее скрывает и показывает вновь,
нужно удалять, причем удалять после установки фокуса в RichEdit
либо не удалять, но тогда и предотврящать ее создание, но это я уже повторяюсь

либо вообще не показывать RichEdit, а рисовать только его содержимое в основном окне
(кстати, по моему, выделение в этом случае уже не будет отображаться, даже если оно и существует, ну и соответственно сенсорики тоже не будет)

последнее, по-моему - наименее кривой способ, относительно остальных

Автор: yngwie19 19.4.2009, 23:05
GremlinProg, а сообщение о нажатой левой кнопки мыши не вернет курсор обратно?

Автор: GremlinProg 19.4.2009, 23:20
Цитата(yngwie19 @  20.4.2009,  01:05 Найти цитируемый пост)
а сообщение о нажатой левой кнопки мыши не вернет курсор обратно?

ты о чем? куда обратно?

Автор: yngwie19 19.4.2009, 23:39
GremlinProg, ну если мы его уничтожим, что при нажатии левой кнопки мыши он не вернется в RichEdit?

Автор: GremlinProg 19.4.2009, 23:44
если уничтожать, то уничтожать свякий раз при установке фокуса,
т.е. на событие WM_SETFOCUS, смотри свои темы, я же об этом писал

Автор: yngwie19 20.4.2009, 08:18
GremlinProg, при обработке WM_SETFOCUS GetLastError() акже возвращает "Отказано в доступе"

Автор: GremlinProg 20.4.2009, 11:34
процедура окна RichEdit'а:
Код

...
case WM_SETFOCUS:
        rv = ::CallWindowProc(...);
        ::DestroyCaret();
        return rv;
...


Автор: yngwie19 20.4.2009, 18:43
Цитата(GremlinProg @  20.4.2009,  11:34 Найти цитируемый пост)
CallWindowProc(...);

а это зачем, что это вообще за функция

Автор: GremlinProg 20.4.2009, 19:24
это подсказка тебе, что код актуален только при использовании субклассинга (любого субклассинга)

Автор: yngwie19 20.4.2009, 22:15
GremlinProg, боюсь даже спросить что такое субклассинг  smile 

Автор: yngwie19 20.5.2009, 12:23
GremlinProg, ну вот вроде разобрался с субклассингом, но мочему-то все равно курсор не исчезает.
Код

#include "stdafx.h"

LRESULT CALLBACK RichProc(HWND,UINT,WPARAM,LPARAM);

HWND hMainWnd = 0; 
HWND hWndRichEdit = 0;
WNDPROC hPrevWndProc;

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
        switch(uMsg) 
        { 
            case WM_DESTROY: 
                PostQuitMessage(0); 
            break; 

            case WM_SIZE: 
                MoveWindow(hWndRichEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); 
            break; 
    }     
        return DefWindowProc(hWnd, uMsg, wParam, lParam); 
} 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{ 
    WNDCLASSEX wc = {0}; 

    wc.cbSize = sizeof(wc); 
    wc.lpfnWndProc = MainWndProc; 
    wc.hInstance = hInstance; 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); 
    wc.lpszClassName = _T("MainWndClass"); 
    RegisterClassEx(&wc); 

    hMainWnd = CreateWindowEx(0, wc.lpszClassName, _T("TestApp"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
    200, 200, 400, 365, NULL, NULL, hInstance, NULL); 

    LoadLibrary("Msftedit.dll"); 

    hWndRichEdit = CreateWindowEx(0, _T("RichEdit50W"), NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | 
    ES_MULTILINE | WS_VSCROLL | WS_HSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_READONLY, 
    0, 0, 380, 320, hMainWnd, NULL, hInstance, NULL); 

    HANDLE hFile = CreateFile(_T("C:\\2.rtf"), GENERIC_READ, FILE_SHARE_READ, 
    0, OPEN_EXISTING, 0, 0); 
    if(hFile != INVALID_HANDLE_VALUE) 
    { 
    DWORD dwRead = 0, dwSize = GetFileSize(hFile, NULL); 
    char *buf = new char[dwSize+1]; 
    ReadFile(hFile, buf, dwSize, &dwRead, 0); 
    buf[dwRead] = '\0'; 
    CloseHandle(hFile); 

    SetWindowTextW(hWndRichEdit, (wchar_t*)buf); // передаётся ANSI строка. работает. тестировалось в WinXP SP2. 
    // при портировании на другие версии ОС Windows может не работать. 

    hPrevWndProc = (WNDPROC)SetWindowLong(hWndRichEdit,GWL_WNDPROC,(LONG)RichProc);

    delete []buf; 
} 

    MSG msg; 
    while(GetMessage(&msg, 0, 0, 0)) 
    { 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
    } 

return 0; 
}

LRESULT CALLBACK RichProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_SETFOCUS:
            LRESULT rv = CallWindowProc(hPrevWndProc,hwnd,msg,wParam,lParam);
            DestroyCaret();
            return rv;
        return CallWindowProc(hPrevWndProc,hwnd,msg,wParam,lParam);
    }
}

Автор: GremlinProg 20.5.2009, 12:29
Цитата(yngwie19 @  20.5.2009,  14:23 Найти цитируемый пост)
но мочему-то все равно курсор не исчезает

попробуй просто не вызывать процедуру окна предка на WM_SETFOCUS:
Код

case WM_SETFOCUS:
  return 0;

Автор: yngwie19 20.5.2009, 12:51
все равно не исчезает. Попробуй пожалуйста сам. Код выше рабочий

Автор: Andrey44 20.5.2009, 13:01
А может попробовать на WM_SETFOCUS реагировать смещением каретки за пределы контрола?
Код

::SetCaretPos(-1, -1);

?

Автор: GremlinProg 20.5.2009, 13:05
у меня все работает нормально, курсора нет, если перекрывать так:
Код

LRESULT CALLBACK RichProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_SETFOCUS:
        case WM_KILLFOCUS:
            return 0;
    }
    return CallWindowProc(hPrevWndProc,hwnd,msg,wParam,lParam);
}

без WM_KILLFOCUS тоже работает (я его поставил только чтобы предок даже не пытался удалять курсор)

а вот этот вариант - не работает, сам найди отличия:
Цитата(yngwie19 @  20.5.2009,  14:23 Найти цитируемый пост)

   switch (msg)    {
        case WM_SETFOCUS:
            LRESULT rv = CallWindowProc(hPrevWndProc,hwnd,msg,wParam,lParam);
            DestroyCaret();
            return rv;
        return CallWindowProc(hPrevWndProc,hwnd,msg,wParam,lParam);
    }

причем компилятор на это четко дает понять: не все пути к выходу перекрыты (прим. пер.)
не знаю, как у тебя он мог хотя бы даже просто показывать содержимое рич-окна (хотя бы после первого ресайза)

Автор: GremlinProg 20.5.2009, 13:34
кстати, yngwie19, сейчас вот подумал
может ты имеешь ввиду еще и курсор в виде каретки?
так им так же можно спокойно управлять:
Код

case WM_SETCURSOR:
  if( LOWORD(lParam) == HTCLIENT ){
    ::SetCursor( ::LoadCursor(NULL,IDC_ARROW) );
    return TRUE;
  }
  break;


Добавлено через 4 минуты и 50 секунд
Цитата(GremlinProg @  20.5.2009,  15:05 Найти цитируемый пост)
курсора нет

Цитата(GremlinProg @  20.5.2009,  15:05 Найти цитируемый пост)
удалять курсор

тут я смешал понятия, имелась ввиду конечно каретка, а не курсор
курсора касается только последний пост

Автор: mes 20.5.2009, 13:40
Цитата(GremlinProg @  20.5.2009,  12:34 Найти цитируемый пост)
и курсор в виде каретки?


GremlinProg, боюсь ошибиться, но всегда полагал, что каретка это маркер позиции при редактировании в текстовом контроле, а по коду изменяете "мышкин" маркер.   smile 

Автор: GremlinProg 20.5.2009, 13:46
да, обычно так и полагают, когда говорят о текстовых редакторах, видимо поэтому я и не сразу обратил внимание замечание в посте yngwie19:
Цитата(yngwie19 @  20.5.2009,  14:23 Найти цитируемый пост)
GremlinProg, ну вот вроде разобрался с субклассингом, но мочему-то все равно курсор не исчезает.

в общем случае, курсор и каретка - это не одно и то же

Автор: yngwie19 20.5.2009, 14:21
вообщем что-то у меня не получается, и Я сам запутался в этих понятиях. Мне нужно удалить вот это:
http://ipicture.ru/Gallery/Viewfull/19186510.html

Автор: GremlinProg 20.5.2009, 14:55
в приложении exe
а здесь код, проекта, логика по-прежнему не изменилась: перекрываем WM_SETFOCUS
Код

#include <windows.h>
#include <tchar.h>

#pragma comment(lib,"user32")

HWND hMainWnd = 0; 
HWND hWndRichEdit = 0;
WNDPROC hPrevWndProc;

LRESULT CALLBACK RichProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_SETFOCUS:
        case WM_KILLFOCUS:
            return 0;
    }
    return CallWindowProc(hPrevWndProc,hwnd,msg,wParam,lParam);
}
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
        switch(uMsg) 
        { 
            case WM_DESTROY: 
                PostQuitMessage(0); 
            break; 

            case WM_SIZE: 
                MoveWindow(hWndRichEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); 
            break; 
    }     
        return DefWindowProc(hWnd, uMsg, wParam, lParam); 
} 

int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{ 
    WNDCLASSEX wc = {0}; 

    wc.cbSize = sizeof(wc); 
    wc.lpfnWndProc = MainWndProc; 
    wc.hInstance = hInstance; 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); 
    wc.lpszClassName = _T("MainWndClass"); 
    RegisterClassEx(&wc); 

    hMainWnd = CreateWindowEx(0, wc.lpszClassName, _T("TestApp"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
    200, 200, 400, 365, NULL, NULL, hInstance, NULL); 

    LoadLibrary(_T("Msftedit.dll")); 

    hWndRichEdit = CreateWindowEx(0, _T("RichEdit50W"), NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | 
    ES_MULTILINE | WS_VSCROLL | WS_HSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_READONLY, 
    0, 0, 380, 320, hMainWnd, NULL, hInstance, NULL); 
    //
    HRSRC hrsrc        = ::FindResource(hInstance,_T("RTF"),RT_RCDATA);
    HGLOBAL hmem    = ::LoadResource(hInstance,hrsrc);
    SIZE_T rcsize    = ::SizeofResource(hInstance,hrsrc);
    char *buf        = new char[rcsize+1]; 
    buf[rcsize]        = '\0';
    memmove(buf,::LockResource(hmem),rcsize);
    SetWindowTextW(hWndRichEdit, (wchar_t*)buf); // передаётся ANSI строка. работает. тестировалось в WinXP SP2. 
    // при портировании на другие версии ОС Windows может не работать. 

    hPrevWndProc = (WNDPROC)SetWindowLong(hWndRichEdit,GWL_WNDPROC,(LONG)RichProc);

    delete []buf; 

    MSG msg; 
    while(GetMessage(&msg, 0, 0, 0)) 
    { 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
    } 

return 0; 
}

ресурс только зашит прямо в exe, чтобы не таскать за ним rtf'ы

Автор: yngwie19 20.5.2009, 15:15
GremlinProg, Спасибо тебе большое, у меня все получилось завтра +1 поставлю, т.к сегодня уже нельзя. smile 
А скажи пожалуйста как сделать чтобы когда мышка проходит наж этим субклассированным окном, то она принимала бы другой облик ну например в виде стрелки. 

Автор: GremlinProg 20.5.2009, 15:19
Цитата(yngwie19 @  20.5.2009,  17:15 Найти цитируемый пост)
как сделать чтобы когда мышка проходит наж этим субклассированным окном, то она принимала бы другой облик ну например в виде стрелки

уже сказал: http://forum.vingrad.ru/index.php?showtopic=256173&view=findpost&p=1873249

Автор: yngwie19 20.5.2009, 15:43
Большое тебе спасибо!!!!

Автор: yngwie19 22.5.2009, 09:22
Кстати А почему у меня вот так не меняется?
Код

SetClassLong(hWndRichEdit,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));

Мне нужно это окно заново перерисовать.?

Автор: GremlinProg 22.5.2009, 10:25
Цитата(yngwie19 @  22.5.2009,  11:22 Найти цитируемый пост)
А почему у меня вот так не меняется?

richedit, как и edit, не использует курсор класса
он меняет его в процедуре окна: http://forum.vingrad.ru/index.php?showtopic=256173&view=findpost&p=1873249

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)