Hey, I was working on a program in windows API where there are multiple edit boxes and there are push buttons. If a pushbutton is clicked, I want the program to find the edit box that the cursor is in and add the character to that edit box. Now I know how to add the character to the box but I don't know how to determine which edit box that the cursor is in. Any Help?

Recommended Answers

All 6 Replies

Yea, try this...

GetFocus  The GetFocus function retrieves the handle to the window that has the keyboard focus, if the 
          window is associated with the calling thread's message queue. 

HWND GetFocus(VOID)
 
Parameters  This function has no parameters. 

Return Values

The return value is the handle to the window with the keyboard focus. If the calling thread's message 
queue does not have an associated window with the keyboard focus, the return value is NULL. 

Remarks

Even if GetFocus returns NULL, another thread's queue may be associated with a window that has the keyboard focus. 

Use the GetForegroundWindow function to retrieve the handle to the window with which the user is currently working. You can associate your thread's message queue with the windows owned by another thread by using the AttachThreadInput function.

Ok, I tried this but it didn't work.

case IDC_AWA:
			{
				HWND hRetrieve = GetFocus();
				int length = GetWindowTextLength(hRetrieve);
				LPCSTR pszText = "á";
				SendMessage(hRetrieve, EM_SETSEL, length, length + 1);
				SendMessage(hRetrieve, EM_REPLACESEL, true,(LPARAM) pszText); 
			}

Ahh! goody, sorry about that! You are right. It doesn't work. I'm afraid the solution is a bit more complex. Basically, when a textbox has the focus and you click some other control such as a button, the edit control will lose the keyboard focus and windows will send it a WM_KILLFOCUS event just before it changes the focus to whatever. The problem with that is that in order for you to intercept that WM_KILLFOCUS message received by the edit control just about to lose the keyboard focus, you need to have subclassed the edit control itself (the window procedure of edit controls is in Windows). I wrote a quick PowerBASIC program to test out my theory and it worked perfectly. I put a button at the top of the Form, and generated five or six edit controls within a for loop in the WM_CREATE handler. Within that for loop I subclassed all the edit controls. Within the subclass proc I tested for WM_KILLFOCUS messages. When I got one I stored the handle of the edit control receiving a WM_KILLFOCUS message at offset zero within four extra .cbWndExtra bytes I allocated in the main Window's class structure. When you click the button at the top of the form a text string is written to whatever of the six edit controls had the focus befoire you clicked the button. Here is the PowerBASIC SDK style code. If you are an Api coder it will be quite clear to you, as the general structure of WinMain and WndProc() as well as everything else is about the same. Sorry its not in C++ code. If you don't understand it I'll redo it in C++. It would probably take me a half hour or so, and its Sunday afternoon, and my wife wants me to go to the store for groceries. Believe me though, I tried it and it works great.

#Compile Exe
#Include "Win32api.inc"
%IDC_BUTTON = 1250
%IDC_EDIT   = 1251
Global fnOldEditProc As Dword


Function fnNewEditProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  Select Case As Long wMsg
    Case %WM_KILLFOCUS
      Call SetWindowLong(GetParent(hWnd),0,hWnd)
      fnNewEditProc=0
  End Select

  fnNewEditProc=CallWindowProc(fnOldEditProc,hWnd,wMsg,wParam,lParam)
End Function


Function WndProc(Byval hWnd As Long,Byval wMsg As Long,Byval wParam As Long,Byval lParam As Long) Export As Long
  Select Case wMsg
    Case %WM_CREATE
      Local hButton As Dword,hEdit As Dword
      Local hIns As Dword
      Register i As Long
      hIns=GetModuleHandle(Byval 0)
      hButton=CreateWindow("button","Button #1",%WS_CHILD Or %WS_VISIBLE,85,20,100,25,hWnd,%IDC_BUTTON,hIns,0)
      For i=0 To 5
        hEdit=CreateWindowEx(%WS_EX_CLIENTEDGE,"edit","",%WS_CHILD Or %WS_VISIBLE Or %WS_BORDER,10,70+40*i,250,25,hWnd,%IDC_EDIT+i,hIns,Byval 0)
        fnOldEditProc=SetWindowLong(hEdit,%GWL_WNDPROC,CodePtr(fnNewEditProc))
      Next i
      WndProc=0
      Exit Function
    Case %WM_COMMAND
      Select Case Lowrd(wParam)
        Case %IDC_BUTTON
          Local szString As Asciiz*64
          szString="SetWindowText() Put This Here!"
          Call SetWindowText(GetWindowLong(hWnd,0),szString)
      End Select
      WndProc=0
      Exit Function
    Case %WM_DESTROY
      Call PostQuitMessage(0)
      WndProc=0
      Exit Function
  End Select

  WndProc=DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function


Function Winmain(Byval hIns As Long, Byval hPrev As Long, Byval lpCL As Asciiz Ptr, Byval iS As Long) As Long
  Local Msg As tagMsg
  Local winclAss As WndClAssEx
  Local szAppName As Asciiz * 32
  Local hWnd As Dword

  szAppName="StrangeBehavior"
  winclAss.lpszClAssName=Varptr(szAppName)
  winclAss.lpfnWndProc=Codeptr(WndProc)
  winclAss.cbSize=Sizeof(winclAss)
  winclAss.style=%CS_HREDRAW Or %CS_VREDRAW
  winclAss.cbClsExtra=0
  winclAss.cbWndExtra=4
  winclAss.hInstance=hIns
  winclAss.hIcon=LoadIcon(%NULL, Byval %IDI_APPLICATION)
  winclAss.hCursor=LoadCursor(%NULL, Byval %IDC_ARROW)
  winclAss.hbrBackground=%COLOR_BTNFACE+1
  winclAss.lpszMenuName=%NULL
  winclAss.hIconSm=0
  RegisterClAssEx winclAss
  hWnd=CreateWindow(szAppName,"Caption = Form28",%WS_OVERLAPPEDWINDOW,200,100,280,350,0,0,hIns,Byval 0)
  Call ShowWindow(hWnd,iS)
  Call UpdateWindow(hWnd)
  While GetMessage(Msg,%NULL,0,0)
    TranslateMessage Msg
    DispatchMessage Msg
  Wend

  Function=msg.wParam
End Function

Felt bad about providing a solution in another language in a C++ forum, so here it is in C++. First the include, then Main.cpp. There are about five edit controls. Set the focus in one of them, then click the button at top.

//WinTypes.h
#ifndef WINTYPES_H
#define WINTYPES_H

typedef struct    WindowsEventArguments
{
 HWND             hWnd;
 WPARAM           wParam;
 LPARAM           lParam;
 HINSTANCE        hIns;
}WndEventArgs,    *lpWndEventArgs;


struct EVENTHANDLER
{
 unsigned int    Code;
 long            (*fnPtr)(lpWndEventArgs);
};

#endif
//Main.cpp  - GoodysProblem
#include <windows.h>
#include <tchar.h>
#include "WinTypes.h"
#define BTN_BUTTON1 2000
#define IDC_EDIT    3000
EVENTHANDLER EventHandler[3]; 
WNDPROC fnOldEditProc;


long __stdcall fnEditSubClass(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 if(msg==WM_KILLFOCUS)                           //This procedure is a 'sub class 'hook'
 {                                               //into the internal 'edit' class window
    SetWindowLong(GetParent(hwnd),0,(long)hwnd); //procedure within windows.  Its purpose
    return 0;                                    //is to 'hook' WM_KILLFOCUS messages.  When
 }                                               //it gets one it persists it to the main
                                                 //window's .cbWndExtra bytes.
 return CallWindowProc(fnOldEditProc,hwnd,msg,wParam,lParam);
}


long fnWndProc_OnCreate(lpWndEventArgs Wea)           
{
 HWND hCtl;
                                                     
 Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance; 
 hCtl=CreateWindow
 (
   _T("button"),
   _T("Button #1"),
   WS_CHILD | WS_VISIBLE,
   70,20,150,30,
   Wea->hWnd,
   (HMENU)(BTN_BUTTON1),
   Wea->hIns,
   NULL
 );
 for(unsigned int i=0;i<6;i++)
 {
     hCtl=CreateWindowEx
     (
       WS_EX_CLIENTEDGE,
       _T("edit"),
       _T(""),
       WS_CHILD|WS_VISIBLE,
       10,70+40*i,265,25,
       Wea->hWnd,
       (HMENU)(IDC_EDIT+i),
       Wea->hIns,
       0
     );
     fnOldEditProc=
     (WNDPROC)SetWindowLong
     (
       hCtl,
       GWL_WNDPROC,
       (LONG)fnEditSubClass
     );
 } 

 return 0;                                             
}


long fnWndProc_OnCommand(lpWndEventArgs Wea)     //When you press the button the text below is put      
{                                                //in the edit control whose hWnd is stored at offset     
 switch(LOWORD(Wea->wParam))                     //zero in the .cbWndExtra bytes.  It got put there
 {                                               //when one of the edit controls lost focus as picked
  case BTN_BUTTON1:                              //up in the sub class proc.
    SetWindowText((HWND)GetWindowLong(Wea->hWnd,0),_T("This Edit Control Just Lost Focus!"));
    break;
 }
  
 return 0;                                             
}


long fnWndProc_OnClose(lpWndEventArgs Wea)            
{                                                     
 if(MessageBox(Wea->hWnd,_T("Do You Wish To Exit This App?"),_T("Exit Check?"),MB_YESNO)==IDYES)
 {
   DestroyWindow(Wea->hWnd);
   PostQuitMessage(WM_QUIT);
 }

 return 0;
}


long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
{
 WndEventArgs Wea;                           
                                             
 for(unsigned int i=0;i<3;i++)               
 {                                           
     if(EventHandler[i].Code==msg)           
     {                                       
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;  //less crap).
        return (*EventHandler[i].fnPtr)(&Wea);
     }
 }

 return (DefWindowProc(hwnd,msg,wParam,lParam));
}


void AttachEventHandlers(void)      //This procedure is called from WinMain() and associates
{                                   //Windows messages with the procedure to handle them.
 EventHandler[0].Code=WM_CREATE,    EventHandler[0].fnPtr=fnWndProc_OnCreate;
 EventHandler[1].Code=WM_COMMAND,   EventHandler[1].fnPtr=fnWndProc_OnCommand;
 EventHandler[2].Code=WM_CLOSE,     EventHandler[2].fnPtr=fnWndProc_OnClose;
}


int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{                                   
 TCHAR szClassName[]=_T("StrangeBehavior"); 
 WNDCLASSEX wc;                     
 MSG messages;                     
 HWND hWnd;                        

 AttachEventHandlers();                                   
 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=CS_DBLCLKS;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=4;
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0; 
 RegisterClassEx(&wc);
 hWnd=CreateWindow(szClassName,_T("StrangeBehavior"),WS_OVERLAPPEDWINDOW,200,100,300,360,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
  TranslateMessage(&messages);
  DispatchMessage(&messages);
 }

 return messages.wParam;
}

I'm having troubles implementing your code into mine. I used resource files to create my buttons and edit boxes and I'm not using the window for this, I'm just using a dialog box here is some of my code.

The resource file:

IDD_MAIN2 DIALOG DISCARDABLE  0, 0, 650, 151
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Spanish Word Editor"
FONT 8, "MS Sans Serif"
BEGIN
    EDITTEXT        IDC_STEXT,0,7,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ETEXT,60,7,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_POSTEXT,120,7,50,14,ES_AUTOHSCROLL
    LTEXT           "Conjugations(only if verb is the Part of speech)",IDC_STATIC,25,21,150,8
    LTEXT           "Present          Present Progressive          Preterite                   Imperfect             Past Progressive             Future                   Conditional        Present Subjunctive   Imperfect Subjunctive",IDC_STATIC,78,35,600,8;
    LTEXT           "Yo",IDC_STATIC,0,49,150,8
    LTEXT           "Tú",IDC_STATIC,0,63,150,8
    LTEXT           "Usted/Él/Ella",IDC_STATIC,0,77,150,8
    LTEXT           "Nosotros",IDC_STATIC,0,91,150,8
    LTEXT           "Vosotros",IDC_STATIC,0,105,150,8
    LTEXT           "Ustedes/Ellos/Ellas",IDC_STATIC,0,119,150,8
    EDITTEXT        IDC_YOTEXT,65,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_TUTEXT,65,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ELTEXT,65,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_NOSTEXT,65,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_VOSTEXT,65,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ELLOSTEXT,65,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_PPYOTEXT,130,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PPTUTEXT,130,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PPELTEXT,130,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PPNOSTEXT,130,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PPVOSTEXT,130,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PPELLOSTEXT,130,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_PYOTEXT,195,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PTUTEXT,195,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PELTEXT,195,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PNOSTEXT,195,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PVOSTEXT,195,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PELLOSTEXT,195,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_IYOTEXT,260,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ITUTEXT,260,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_IELTEXT,260,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_INOSTEXT,260,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_IVOSTEXT,260,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_IELLOSTEXT,260,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_PAPYOTEXT,325,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PAPTUTEXT,325,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PAPELTEXT,325,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PAPNOSTEXT,325,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PAPVOSTEXT,325,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PAPELLOSTEXT,325,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_FYOTEXT,390,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_FTUTEXT,390,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_FELTEXT,390,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_FNOSTEXT,390,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_FVOSTEXT,390,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_FELLOSTEXT,390,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_CYOTEXT,455,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_CTUTEXT,455,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_CELTEXT,455,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_CNOSTEXT,455,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_CVOSTEXT,455,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_CELLOSTEXT,455,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_PSYOTEXT,520,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PSTUTEXT,520,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PSELTEXT,520,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PSNOSTEXT,520,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PSVOSTEXT,520,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_PSELLOSTEXT,520,117,50,14,ES_AUTOHSCROLL
    
    EDITTEXT        IDC_ISYOTEXT,585,47,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ISTUTEXT,585,61,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ISELTEXT,585,75,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ISNOSTEXT,585,89,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ISVOSTEXT,585,103,50,14,ES_AUTOHSCROLL
    EDITTEXT        IDC_ISELLOSTEXT,585,117,50,14,ES_AUTOHSCROLL
    
	PUSHBUTTON      "á",IDC_AWA,200,133,12,12
    PUSHBUTTON      "é",IDC_EWA,212,133,12,12
    PUSHBUTTON      "í",IDC_IWA,224,133,12,12
	PUSHBUTTON      "ó",IDC_OWA,236,133,12,12
	PUSHBUTTON      "ú",IDC_UWA,248,133,12,12
    PUSHBUTTON      "ñ",IDC_NWT,260,133,12,12
	PUSHBUTTON      "¿",IDC_UQ,272,133,12,12
	PUSHBUTTON      "¡",IDC_UE,284,133,12,12
    PUSHBUTTON      "&Save",IDC_SAVE,585,133,50,14
END

and here is the dialog procedure that corresponds with it in the .cpp file:

BOOL CALLBACK DlgProc2(HWND hwnd2, UINT Message2, WPARAM wParam2, LPARAM lParam2)
{
	switch(Message2)
	{
		case WM_INITDIALOG:
			// This is where we set up the dialog box, and initialise any default values

			SetDlgItemText(hwnd2, IDC_STEXT,     "    Spanish");
			SetDlgItemText(hwnd2, IDC_ETEXT,     "    English");
			SetDlgItemText(hwnd2, IDC_POSTEXT,   "Part of Speech");
		break;
		case WM_COMMAND:
			switch(LOWORD(wParam2))
			{
			case IDC_AWA:
			{
				int length = GetWindowTextLength(hRetrieve);
				LPCSTR pszText = "á";
				SendMessage(hRetrieve, EM_SETSEL, length, length + 1);
				SendMessage(hRetrieve, EM_REPLACESEL, true,(LPARAM) pszText); 
			}
			break;
			case IDC_EWA:
			{
				HWND edit = GetDlgItem(hwnd2, IDC_ANSQW);
				int length = GetWindowTextLength(edit);
				LPCSTR pszText = "é";
				SendMessage(edit, EM_SETSEL, length, length + 1);
				SendMessage(edit, EM_REPLACESEL, true,(LPARAM) pszText); 
			}
			break;
			case IDC_IWA:
			{
				HWND edit = GetDlgItem(hwnd2, IDC_ANSQW);
				int length = GetWindowTextLength(edit);
				LPCSTR pszText = "í";
				SendMessage(edit, EM_SETSEL, length, length + 1);
				SendMessage(edit, EM_REPLACESEL, true,(LPARAM) pszText); 
			}
			break;
			case IDC_OWA:
			{
				HWND edit = GetDlgItem(hwnd2, IDC_ANSQW);
				int length = GetWindowTextLength(edit);
				LPCSTR pszText = "ó";
				SendMessage(edit, EM_SETSEL, length, length + 1);
				SendMessage(edit, EM_REPLACESEL, true,(LPARAM) pszText); 
			}
			break;
			case IDC_UWA:
			{
				HWND edit = GetDlgItem(hwnd2, IDC_ANSQW);
				int length = GetWindowTextLength(edit);
				LPCSTR pszText = "ú";
				SendMessage(edit, EM_SETSEL, length, length + 1);
				SendMessage(edit, EM_REPLACESEL, true,(LPARAM) pszText); 
			}
			break;
			case IDC_NWT:
			{
				HWND edit = GetDlgItem(hwnd2, IDC_ANSQW);
				int length = GetWindowTextLength(edit);
				LPCSTR pszText = "ñ";
				SendMessage(edit, EM_SETSEL, length, length + 1);
				SendMessage(edit, EM_REPLACESEL, true,(LPARAM) pszText); 
			}
			break;
			case IDC_UQ:
			{
				HWND edit = GetDlgItem(hwnd2, IDC_ANSQW);
				int length = GetWindowTextLength(edit);
				LPCSTR pszText = "¿";
				SendMessage(edit, EM_SETSEL, length, length + 1);
				SendMessage(edit, EM_REPLACESEL, true,(LPARAM) pszText); 
			}
			case IDC_SAVE:	
				DoFileSave(hwnd2);
				EndDialog(hwnd2, 0);
				hwndGoto = NULL;
			break;
			}
		break;
		
		case WM_CLOSE:
			EndDialog(hwnd2, 0);
			hwndGoto = NULL;
		break;
		
		default:
			return FALSE;
	}
	return TRUE;
}

Hope somebody else can help you with that Goody. I simply don't use the Windows Dialog Engine at all. I'm not absolutely sure, but I believe the same general principals will be involved as in the code I showed. Basically, when you click a button in a window (whether it be a CreateWindowEx() window or a window created by the Windows Dialog Engine), the focus will be transferred from the edit box with focus, to the button. This activity is a complex one in that it involves many messages. First you'll have various mouse messages sent to the button. Then you'll have various kill focus & set focus messages. None of these are going to occur within your dialog procedures, and only by utilizing these messages will you be able to accomplish what you described you want to accomplish. So, if you insist on continuing what you are trying to do, you are going to have to find out how you are going to do it within the framework you have chosen to use, and that appears to be the Windows Dialog Engine.

In my opinion use of Dialog Boxes for major and complicated user interfaces - esapecially ones involving extremely unusual behavior such as you are trying to implement, is a very bad idea. While the code I provided might seem complicated, it is my opinion that if you ever achieve this within the framework of the Windows Dialog Engine, your final code will be much, much worse. All I can say is perhaps someone more familiar with Dialog boxes can show you a better way to do it.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.