Click here to Skip to main content
15,888,210 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello!

I want to plot serial data using the Win32 api. However, the SetPixel function is ploting only part of the data. It doesnt plot anything below a certain imaginary line of the window, over that line it works perfectly. Does anybody know what the problem is?

I believe that the problem is in the second thread. There is a certain point of the window that the SetPixel function doesn't plot data anymore. I also believe that it has to do with the way windows reapaints the window.


Thanks!



C++
/* - Comunicaçao Serial Entre o Microcontrolador e um Computador - */
/* ----------- Recebe Dados do Microcontrolador e Plota ---------- */

// To Do:
    // Verificar o Erro de quando clica duas vezes na tela
    // Verificar o Erro de porque de ve em quando ele recebe dados diferentes
    // Organizar Código
    //




#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

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


#define BUTTON1 1
#define BUTTON2 2
#define IDM_FILE_NEW 3
#define IDM_FILE_OPEN 4
#define IDM_FILE_QUIT 5
#define STOP 6


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/*  Declare */
HWND textfield;
HWND TextBox;
FILE* fp;
HANDLE hCom;
HANDLE Handlethread;
DCB dcb;
BOOL fSuccess;
DWORD WINAPI THREAD1(LPVOID lpParam);
HWND hwnd;
DWORD ExitCode = 0;
int *lpArgPtr;
void AddMenus(HWND);
char textSaved[20];
char textSaved2[]={"Connecting."};
HDC hdc;

/*  Make the class name into a global variable  */
TCHAR szClassName[ ] = _T("EXAME DE SINCOPE VASOVAGAL");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
                 /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = "Menu";                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           _T("EXAME DE SÍNCOPE VASOVAGAL"),       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           700,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//Caso o botao1 seja apertado;//
int     gwtstat = 0;
char *  t = &textSaved[0];
char pcCommPort[50] = "\\\\.\\COM4";
char SuceText[] = {"Connected"};
char stopedcon[]= {"Connection Stoped"};
char ErrorText[] = {"Error Connecting"};
char ConnectionError[] = {"Port Not Connected"};
int j;

/*--- Estrutura para quando pintar a tela ---*/
PAINTSTRUCT ps;
TEXTMETRIC  tm;     //Decide o tamanho das letras
TCHAR       teste[]={"Exame:"};

    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:

        AddMenus(hwnd);//Adiciona Menus a janela

        TextBox = CreateWindow("EDIT",
                              "",
                              WS_BORDER | WS_CHILD | WS_VISIBLE,
                              10, 540,400,20,
                              hwnd,NULL,NULL,NULL);

        CreateWindow("BUTTON",
                     "SAVE",
                     WS_VISIBLE | WS_CHILD | WS_BORDER,
                     420, 540, 70, 20,
                     hwnd, (HMENU) 1, NULL, NULL);

        CreateWindow("BUTTON",
                     "START",
                     WS_VISIBLE | WS_CHILD | WS_BORDER,
                     420, 580, 70, 20,
                     hwnd, (HMENU) 2, NULL, NULL);

        CreateWindow("BUTTON",
                     "STOP",
                     WS_VISIBLE | WS_CHILD | WS_BORDER,
                     300, 580, 70, 20,
                     hwnd, (HMENU) 6, NULL, NULL);
                break;

    case WM_PAINT:
                hdc = BeginPaint(hwnd,&ps);
                FillRect(hdc,&ps.rcPaint,(HBRUSH)(COLOR_WINDOW+1)); //Pinta a Janela de Branco;
                SelectObject(hdc, GetStockObject( NULL_BRUSH ) );
                for (j=10;j<500;j++){
                    SetPixel(hdc,j,0,RGB(0,0,0));
                }
                 for (j=10;j<500;j++){
                    SetPixel(hdc,j,255,RGB(0,0,0));
                }
                  for (j=10;j<500;j++){
                    SetPixel(hdc,j,510,RGB(0,0,0));
                }
                //Rectangle(hdc,10,110,500,300);
                TextOut(hdc,1,515,teste,strlen(teste));    //How to change BackGround Colour? With SetBkColour
                EndPaint(hwnd,&ps);
                break;

    case WM_COMMAND:
        switch (LOWORD(wParam)){
            case BUTTON1:

                gwtstat = GetWindowText(TextBox,t, 20);
                ::MessageBox(hwnd,textSaved,textSaved,MB_OK);
                fopen("info.txt","a+");
                fwrite(teste,1,sizeof(teste),fp);
                //TerminateThread(Handlethread,ExitCode);

                break;

            case BUTTON2:
                hCom = CreateFile( pcCommPort,
                                GENERIC_READ | GENERIC_WRITE,
                                0,    // must be opened with exclusive-access
                                NULL, // no security attributes
                                OPEN_EXISTING, // must use OPEN_EXISTING
                                0,    // not overlapped I/O
                                NULL  // hTemplate must be NULL for comm devices
                    );


                if (hCom == INVALID_HANDLE_VALUE)
                {
                    ::MessageBox(hwnd,ConnectionError,ConnectionError,MB_OK);
                   return (1);
                }


               fSuccess = GetCommState(hCom, &dcb);

               if (!fSuccess)
               {    //failed
                    return (2);
               }

                dcb.BaudRate = CBR_9600;     // set the baud rate
                dcb.ByteSize = 8;             // data size, xmit, and rcv
                dcb.Parity = NOPARITY;        // no parity bit
                dcb.StopBits = TWOSTOPBITS;    // one stop bit

                fSuccess = SetCommState(hCom, &dcb);

                if (!fSuccess)
                {
                ::MessageBox(hwnd,ConnectionError,ConnectionError,MB_OK);
                  return (3);
                }else{

                    Handlethread = CreateThread(NULL,0,THREAD1,lpArgPtr,0,NULL);
                }
                ::MessageBox(hwnd,SuceText,SuceText,MB_OK);
                break;
            case IDM_FILE_NEW:
                Beep(100, 100);
                break;
            case IDM_FILE_OPEN:
                Beep(50, 100);
                break;
            case IDM_FILE_QUIT:
                SendMessage(hwnd,WM_CLOSE,0,0);
                break;
            case STOP:

                if (CloseHandle(hCom)==0){
                ::MessageBox(hwnd,ErrorText,NULL,MB_OK);
                }
                else{
                ::MessageBox(hwnd,stopedcon,stopedcon,MB_OK);
                }

                break;
        }

    case WM_DESTROY:
            //PostQuitMessage (0);       //send a WM_QUIT to the message queue

            break;

            default:                      /* for messages that we don't deal with */
                return DefWindowProc (hwnd, message, wParam, lParam);
            }

    return 0;
}


void AddMenus(HWND hwnd)
              {
              HMENU hMenubar;
              HMENU hMenu;
              hMenubar = CreateMenu();
              hMenu = CreateMenu();

              AppendMenuW(hMenu,MF_STRING, IDM_FILE_NEW, L"&New");
              AppendMenuW(hMenu,MF_STRING, IDM_FILE_OPEN, L"&Open");
              AppendMenuW(hMenu,MF_SEPARATOR, 0,NULL);
              AppendMenuW(hMenu,MF_STRING, IDM_FILE_QUIT, L"&Quit");
              AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR) hMenu, L"&File");

              SetMenu(hwnd, hMenubar);
              }

    //SECOND THREAD;

DWORD WINAPI THREAD1(LPVOID lpParam){


    //PROBLEM STARTS HERE

        printf("I am inside the thread\n");

            int i = 0;
            int y = 0;
            bool tx;
            char PlotData[500] = {0};
            DWORD num;
            byte in[100]={0};

        while(1){

                tx = ReadFile(hCom,&in,2,&num,NULL);
                if (tx==0||num!=2){
                    printf("ERROR");
                    if (CloseHandle(hCom)==0){
                    ExitThread(ExitCode);
                }
                }else{
                printf("%x\t",(in[0]));
                }
                if(i>=500){

                    for(y=1;y<500;y++){
                        hdc = GetDC(hwnd);
                        SetPixel(hdc,y,PlotData[y],RGB(255,255,255));
                        ReleaseDC(hwnd,hdc);
                        PlotData[y-1] = PlotData[y];
                        PlotData[499] = (255 - in[0]);
                    }

                    for(y=0;y<500;y++){
                        hdc = GetDC(hwnd);
                        SetPixel(hdc,y,PlotData[y],RGB(255,0,0));
                        ReleaseDC(hwnd,hdc);
                    }


                }else if (i<500){
                        //hdc = GetDC(hwnd);
                        PlotData[i] = (255 - in[0]);
                        //ReleaseDC(hwnd,hdc);
                        i++;
                }
            }


        return NULL;
}
Posted
Updated 28-Mar-15 7:40am
v3
Comments
Sergey Alexandrovich Kryukov 27-Mar-15 22:31pm    
To start with, SetPixel will be prohibitively slow...
Will you add <pre lang="C++"> ... your code ... </pre> formatting, to make your code sample more readable?
—SA
Member 11514006 28-Mar-15 13:28pm    
Hey Sergey!

I actualy didn't know this. Thanks for telling me!Someone formated it for me. Ok, I've been told that SetPixel is too slow, but I am afraid I don't know what else to do. Do you have tips? Could you recommend a real-time plot library?
Thanks,
Thiago
Sergey Alexandrovich Kryukov 28-Mar-15 16:40pm    
Nothing is real-time in Windows, despite some names used in API...
—SA
Richard MacCutchan 28-Mar-15 4:34am    
You need to explain in more detail what exactly you expect to happen, and where in your code the failure appears to be.

1 solution

Hey Sergey!

Thiago wrote:
I actualy didn't know this. Thanks for telling me! Someone formatted it for me. Ok, I've been told that SetPixel is too slow, but I am afraid I don't know what else to do. Do you have tips? Could you recommend a real-time plot library?
Thanks,
Thiago
You are welcome.

Some very well-known libraries with advanced graphics are, for example, open-source GTK+ and Qt. But you have to remember than they are cross-platform C++ libraries, can be server as OS abstraction layers and include a lot more than just graphics, in particular, the way to develop UI, and a lot more (in case of Qt). Please see:
http://en.wikipedia.org/wiki/GTK%2B,
http://www.gtk.org,
http://en.wikipedia.org/wiki/Qt_%28software%29,
https://qt-project.org/.

On Windows, many people use MFC, but this is just a pretty thin layer over Win32, and I consider it as pretty ugly, poor and obsolete, always avoided it. Also, it has the proprietary license, no open source, in contrast to new Microsoft products which a getting more and more open with time, but for old MFC, I guess, it's too late. The major benefit, I would say, it that it is supplied with Visual Studio. It can be used as a base for developing mostly in pure Windows API, having less hassles where you are not very interested to dig into Windows API…

You can also try to find something else, according to your needs. Consider reviewing these sets of links:
http://en.cppreference.com/w/cpp/links/libs,
http://en.wikipedia.org/wiki/Category:C%2B%2B_libraries,
http://stanford.edu/~stepp/cppdoc.

[EDIT]

I later realized that you might not be interested in general graphics (despite of your general-graphics code sample). Using the general graphics libraries, you can always develop your chart/plot libraries (as I used to do, and not once), but you may be interested only in more specialized topic, charts, plotting. Consider, for example, http://code.google.com/p/matplotpp.

Also, did you consider using C++/CLI instead of C++? It can be used for both native Windows (or cross-platform development), as well as CLI (.NET). .NET is very different, it is bound with its own graphics libraries, it is well abstracted from native OS, and there are a lot more graphics/plotting/charting libraries for .NET, such as Microsoft Charts library.

Please see:
http://en.wikipedia.org/wiki/C%2B%2B/CLI,
http://www.ecma-international.org/publications/standards/Ecma-372.htm,
http://www.gotw.ca/publications/C++CLIRationale.pdf,
http://msdn.microsoft.com/en-us/library/xey702bw.aspx.

Good luck,
—SA
 
Share this answer
 
v4
Comments
CPallini 28-Mar-15 17:50pm    
5.
Sergey Alexandrovich Kryukov 28-Mar-15 17:58pm    
Thank you, Carlo.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900