LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices

Rate this Entry

A Stand Alone executable QT MsgBox with Stays On Top attribute

Posted 12-13-2012 at 07:59 AM by rainbowsally

A Stand Alone executable QT MsgBox with Stays On Top attribute.

Today's Features:
  • A non-modal qt based dialog/message box that STAYS ON TOP of the window stack.
  • How to center a window on the screen.
  • Using the short optargs to parse the options.

The msgbox utility in the 'extras' folders of the mc2 d/load (see link below) uses xmessage for the display widget. That makes it independent of QT so it can run on any computer that has the X windowing system.

But what about a QT widget?

The kdialog functions could be used and and it's pretty useful and they do get returns from the user. But it launches somewhat slowly and sometimes... well, it doesn't always pop up to the top of the window stack.

[Interesting side note here: When you do set the stays on top flag, it won't center automatically, but that's why we like doing this stuff ourselves -- no built-in limitations. You can verify this problem by messing with the source code. Comment out the 'show' and 'center window' lines and see what happens.]

Let's make a very basic MsgBox (with caps to differentiate it from the xmessage version) that can accept a string input or a file for the message.

This is NOT a 'dialog'. It's a message, such as you might get on a commandline. This can be called from clickable text-based programs for status info, usage notes, etc.

[To make your script clickable, change to the directory at `dirname "$0"`, and if your system can't launch executable shell programs, see if you can find 'shell-exec' here at the blog. I may repost it a bit later. -rs]

The makefile can probably be figured out from the mc2.def if you don't have mc2 (makefile creator 2) available here.

http://www.linuxquestions.org/questi...eration-34648/

Here's all the code jammed into a single source file with a pretty ugly main() function because optargs likes it that way. ;-)


file: src/main.cpp
purpose: source file
Code:
// main.cpp

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QMessageBox>

void dbg(){} // for a non-moving breakpoint

void centerWindow(QWidget* window)
{
// Unreliable if window isn't shown yet
  if(!window->isVisible())
    return;

  int dtx,dty,dtw,dth;
  int winx,winy,winw,winh;
  int x, y;

  QDesktopWidget* dt = qApp->desktop();

dt->availableGeometry().getRect(&dtx,&dty,&dtw,&dth);

  window->geometry().getRect(&winx,&winy,&winw,&winh);

  x = dtx + dtw/2 - winw/2; // x1 should not always be 0
  y = dty + dth/2 - winh/2; // y1 ""

  window->setGeometry(x, y, winw, winh);

// get it up and shown in the right position now.
  qApp->processEvents(); // so far
}


// requires instance of QApplication in main()
void errorMsg(const char* msg)
{  
  QMessageBox* b = new QMessageBox(QMessageBox::Critical, "Error", msg,
                                   QMessageBox::Ok, NULL);
  b->setWindowFlags(Qt::WindowStaysOnTopHint);
  b->show();
  centerWindow(b);
  b->exec();
}

// requires instance of QApplication in main()
void warnMsg(const char* msg)
{
  QMessageBox* b = new QMessageBox(QMessageBox::Warning, "Error", msg,
                                   QMessageBox::Ok, NULL);
  b->setWindowFlags(Qt::WindowStaysOnTopHint);
  b->show();
  centerWindow(b);
  b->exec();
}

// requires instance of QApplication in main()
void infoMsg(const char* msg)
{
  QMessageBox* b = new QMessageBox(QMessageBox::Information, "Notice", msg,
                                   QMessageBox::Ok);
  b->setWindowFlags(Qt::WindowStaysOnTopHint);
  b->show();
  centerWindow(b);
  b->exec();
}


// if you have problems with crashing when your
// apps exit, make the QApplication a static.
// The stack may have collapsed before the app 
// had fully deleted itself.  -rs

static QApplication* app;

int usage(int errcode)
{
// #include "usage_str.dat"
  const char* usage_str = 
    "Usage: MsgBox opt {\"string\" | -f fileName}\n"
    "\n"
    "  Creates a message box with an icon selected by\n"
    "  opt, that displays text from a string (default)\n"
    "  or a file when the -f swicth is invoked\n"
    "\n"
    "  opt may be used to select icons as follows:\n"
    "  -i          : info\n"
    "  -w          : warning\n"
    "  -e          : error\n"
    "\n"
    "Swicth?\n"
    "  Swicth, swicth, swicth.  Well, you know...\n"
    "Something like that. ;-)\n";
  
  if(errcode == 0)
    infoMsg(usage_str);
  else if(errcode == 1)
    warnMsg(usage_str);
  else if(errcode == 2)
    errorMsg(usage_str);
  else
    fprintf(stderr, "%s", usage_str);
  return errcode;
}

int main (int argc, char **argv)
{
  
  dbg();
  
  int opttype = 0;
  char *filename = NULL;
  int index;
  int c;
  
  // buffer for strings or files
  int msgmax = 256;
  char* msgbuf = (char*) malloc(msgmax);  

  // buffer for files only
  size_t inmax = 0;
  char* inbuf = 0;
  
  app = new QApplication(argc, argv);
  
  opterr = 0;

  if(argc < 2)
    return usage(1);
  if(argv[1] && strcmp(argv[1], "--help") == 0)
    return usage(0);
  
  while ((c = getopt (argc, argv, "iwehf:")) != -1)
  {
    switch (c)
    {
      case 'i':
        opttype |= 1;
        break;
      case 'w':
        opttype |= 2;
        break;
      case 'e':
        opttype |= 3;
        break;
      case 'f':
        filename = optarg;
        break;
      case 'h':
        return usage(0);
      case '?':
        if (optopt == 'f')
          fprintf (stderr, "Option -%f requires a file name.\n", optopt);
        else if (isprint (optopt))
          fprintf (stderr, "Unknown option `-%c'.\n", optopt);
        else
          fprintf (stderr,
                   "Unknown option character `\\x%x'.\n",
                   optopt);
        return 1;
      default:
        abort ();
    }
  }
  
  if(!opttype)
    return usage(1);
    
  ////////////////////////////////////////////////
  // showMsg(optype, filename, optind, argc, argv)
    
  FILE* fp;  
  
  if(filename)
  {
    fp = fopen(filename, "r");
    if(!fp)
    {
      fprintf(stderr, "Can't open file '%s'\n", filename);
      abort();
    }
    
    //msgmax = 256;
    //msgbuf = (char*) malloc(msgmax);
    int msglen = 0;
    
    inmax = 256;
    inbuf = (char*)malloc(inmax);
    int inlen;
    while(!feof(fp))
    {
      getline(&inbuf, &inmax, fp);
      inlen = strlen(inbuf);
      // sprinter(msgbuf, &msgmax, &msglen, buf);
      while(inlen > (msgmax - msglen))
      {
        msgmax *= 2;
        msgbuf = (char*)realloc(msgbuf, msgmax);
      }
      
      // copy and point to end of string in one operation
      msglen += sprintf(msgbuf + msglen, "%s", inbuf);    
    }
    fclose(fp);
  }
  else
  {
    // using string from the input, opargs has set the optins
    // at the first non-option which will be our string.
    char* instr;
    instr = argv[optind];
    
    int msglen = strlen(instr);
    if(msglen >= (msgmax - 1))
    {
      msgmax = msglen + 1;
      msgbuf = (char*)realloc(msgbuf, msgmax +1);
    }
    strcpy(msgbuf, instr);
  }
  
  switch(opttype)
  {
    case 1: // info
      infoMsg(msgbuf);
      break;
    case 2: // warning
      warnMsg(msgbuf);
      break;
    case 3: // error
      errorMsg(msgbuf);
      break;
    default:
      ; // noop
  }
  
  free(inbuf);
  free(msgbuf);
  return 0;
}

MsgBox accepts multiple flags in a single switch, so that, for example,
Code:
 MsgBox -if mc2.def
will create an 'i'nfo icon and display the 'f'ile mc2.def

And that brings up an interesting issue with QT MessagBox classes. No scroll bars!

If your message is too long, the message box will create an 'extension' that is not
the same width as the main widget and well... that's not my problem. That's theirs.

But we may have to create an InfoBox as well at some time in the future. A box that
has scrollbars.

And now... the makefile definitions for mc2 which, for you who don't want the mc2 utility, mostly just defines the intermediate and final functions (compile and link) with how they are to be done (the flags) and of course the files that (when changed) will trigger rebuilding whichever other parts may need to be refreshed.

file: mc2.def
purpose: source file
Code:
# mc2.def template created with Makefile Creator 'mc2'

#########################################################################################
# for a bit more QT support use 'mc2 -fetch qt4' and add -lLQ-qt, PREFIX, etc. as needed.

## sandbox path and other new variables
PREFIX = $(HOME)/usr32

## The output file name not including path
OUTNAME = MsgBox

## The directories for sources, (temp) objects, and binary output(s)
BINDIR = .
SRCDIR = src
OBJDIR = o

## What COMPILE should do.
COMPILE = g++ -m32 -c -o
#CFLAGS = -g3
CFLAGS = -O2 # or -g3
INCLUDE = -I/usr/include -I$(PREFIX)/include -I./$(SRCDIR) -I/usr/include/QtGui -I/usr/include/Qt

## What LINK should do.
LINK = g++ -m32 -o
LDFLAGS = -lQtGui 

# to make a statically linked version replace -lLQ-qt (above) 
# with the full path to the static lib such as:
#   $(PREFIX)/lib/libLQ-qt.a # <-- static link this one

LIB = -L/usr/lib -L$(PREFIX)/lib

################################################################
## User Defined Targets

clean:
  @rm -f $(MAIN)
  @rm -f $(OBJ)
  @rm -f *~ */*~ */*/*~ */*/*/*~

force: # used to force execution
[Notice the LDFLAGS has no libs from the HOME/usr32 folder. This app will stand-alone as long as the end user has qt4 installed.]

The executable, with three display modes and two input modes is just a nub over 30K.

That's K, not Megs or Gigs.

The Computer Mad Science Team

:-)
Posted in Uncategorized
Views 632 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 01:10 AM.

Main Menu
Advertisement

My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration