In the included code I've created an application where I periodically update a label. When the application first starts up, updating the timeLabel results in redrawing the entire contents of the application. This can be observed by running the application with the --gtk-debug=updates argument.
When the button on the right side is clicked, the frame that encloses the contents of the window is removed from the widget hierarchy. This results in further updates to the timeLabel only redrawing the label, and not redrawing swapButton.
Why does a frame seem to want to redraw itself even if it doesn't need to?
#include <gtkmm.h>
class MyWindow
: public Gtk::Window
{
public:
MyWindow();
private:
bool timeout();
void toggleUseOfFrame();
Gtk::Frame frame;
Gtk::Label timeLabel;
Gtk::Button swapButton;
Gtk::Box box;
};
MyWindow::MyWindow()
{
// Layout widgets in initial configuration.
box.pack_start( timeLabel, true, true );
box.pack_start( swapButton, true, true );
box.set_homogeneous();
frame.add( box );
add( frame );
show_all();
set_size_request( 100, 50 );
// Setup signal handlers.
Glib::MainContext::get_default()->signal_timeout().connect(
sigc::mem_fun( *this, &MyWindow::timeout ), 1000 );
swapButton.signal_clicked().connect(
sigc::mem_fun( *this, &MyWindow::toggleUseOfFrame ) );
}
// Periodically update the label to force it to redraw.
bool MyWindow::timeout()
{
Glib::DateTime now = Glib::DateTime::create_now_local();
timeLabel.set_text( now.format( "%S" ) );
return true;
}
// If the frame is currently in use remove it. Otherwise add it back.
void MyWindow::toggleUseOfFrame()
{
if( frame.get_parent() ) {
remove();
box.reparent( *this );
}
else {
box.reparent( frame );
add( frame );
}
}
int main( int argc, char* argv[]) {
Glib::RefPtr<Gtk::Application> app =
Gtk::Application::create( argc, argv, "test" );
MyWindow myWindow;
return app->run( myWindow );
}
Related
The method I traditionally use of drawing to an OpenGL canvas with wxWidgets is to trigger a 30 hertz timed refresh() from the current OpenGL canvas, which then generates a "wxEVT_PAINT", which I can propogate out to the rest of the frame. I also bind to the wxEVT_PAINT and call refresh() to catch any frame resizes.
In my programs WITHOUT using wxWidgets AUI, this method has worked flawlessly.
If I try to use AUI however, every time I try binding to wxEVT_PAINT, my paint events never trigger. Sometimes binding to the paint event will even stop other events like the timer from triggering.
Is there some special way that AUI treats events, or the wxEVT_PAINT that I'm missing here? What is the best method to draw to a OpenGL window inside of a AUI managed frame? Can anyone provide hints or examples, as documentation seems to be non-existent on this topic concerning AUI.
Edit: For clarity, and I've added my source code below for anyone who would like to help track down the problem. I've removed the OpenGL portions, as I'm really just trying to get the wxEVT_PAINT to trigger my bound handler in the frame when I resize the window.
GeneratedFrame.h
#ifndef __GENERATEDFRAME_H__
#define __GENERATEDFRAME_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/panel.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/menu.h>
#include <wx/frame.h>
#include <wx/aui/aui.h>
class MainFrame : public wxFrame
{
private:
protected:
wxPanel* m_panelMainView;
wxMenuBar* m_menubar2;
public:
MainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("SimpleAui"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 646,516 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
wxAuiManager m_mgr;
~MainFrame();
};
#endif //__GENERATEDFRAME_H__
GeneratedFrame.cpp
#include "GeneratedFrame.h"
MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
m_mgr.SetManagedWindow(this);
m_mgr.SetFlags(wxAUI_MGR_LIVE_RESIZE);
m_panelMainView = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_panelMainView->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVECAPTION ) );
m_panelMainView->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_INFOBK ) );
m_mgr.AddPane( m_panelMainView, wxAuiPaneInfo() .Name( wxT("MainView") ).Center() .Caption( wxT("Main View") ).MinimizeButton( true ).PinButton( true ).Dock().Resizable().FloatingSize( wxDefaultSize ).Floatable( false ) );
m_menubar2 = new wxMenuBar( 0 );
this->SetMenuBar( m_menubar2 );
m_mgr.Update();
this->Centre( wxBOTH );
}
MainFrame::~MainFrame()
{
m_mgr.UnInit();
}
AppFrame.h
#ifndef __AppFrame_h__
#define __AppFrame_h__
#include "GeneratedFrame.h"
#include "SimpleAuiApp.h"
class AppFrame : public MainFrame
{
public:
// Constructor/Descructor
AppFrame( wxWindow* parent, ApplicationData* pAppData );
~AppFrame( );
// display update (called from main App on an update event)
void UpdateDisplay( );
private:
// pointer to the main data structure
ApplicationData* m_pAppData;
void OnPaint( wxPaintEvent& event );
};
#endif //__AppFrame_h__
AppFrame.cpp
#include "AppFrame.h"
#include "SimpleAuiApp.h"
#include <iostream>
// Constructor for the frame
AppFrame::AppFrame( wxWindow* parent, ApplicationData* pAppData )
: MainFrame( parent )
{
// Pull in the app data pointer
m_pAppData = pAppData;
// Set the size of the inner drawing area of the frame
SetClientSize( 500, 500 );
// Show the frame
Show();
// Layout the frame
Layout();
// Bind to the wxEVT_PAINT event
Bind( wxEVT_PAINT, &AppFrame::OnPaint, this );
}
// Destructor for the frame
AppFrame::~AppFrame( )
{
// stop the update timer for the application, otherwise a timer update
// event can be generated while data is being deleted
if( m_pAppData->m_pTimer )
{
m_pAppData->m_pTimer->Stop( );
}
}
void AppFrame::OnPaint( wxPaintEvent& event )
{
std::cout << "Running AppFrame::OnPaint\n";
UpdateDisplay( );
}
// perform frame update for the display
void AppFrame::UpdateDisplay( )
{
std::cout << "Running AppFrame::UpdateDisplay\n";
}
SimpleAuiApp.h
#ifndef __SimpleAuiApp_h__
#define __SimpleAuiApp_h__
#include <wx/wx.h>
#define DEFAULT_UPDATE_RATE (10) // in Hz (set to 0 for OnIdle)
// Forward declarations
class AppFrame;
struct ApplicationData
{
// constructor
ApplicationData( )
{
m_pFrame = NULL;
m_pTimer = NULL;
m_nDisplayUpdateRate = DEFAULT_UPDATE_RATE;
}
// timer object for frame based updates
wxTimer* m_pTimer;
// rate of display update (in HZ) (0=update on idle)
int m_nDisplayUpdateRate;
// pointer to the main frame instance
AppFrame* m_pFrame;
};
// Main application class
// (derived from the wxWidget App class)
class SimpleAuiApp : public wxApp
{
public:
SimpleAuiApp( );
virtual ~SimpleAuiApp( );
// the main application data structure
ApplicationData m_AppData;
private:
// called by wxApp when starting up, program setup should be done here
bool OnInit( );
// called by wxApp when shutting down, program cleanup should be done here
int OnExit( );
// When running with "fixed" framerate, called for each timer event (frame)
void OnTimer( wxTimerEvent& event );
};
DECLARE_APP( SimpleAuiApp )
#endif //__SimpleAuiApp_h__
SimpleAuiApp.cpp
#include <wx/wx.h>
#include "SimpleAuiApp.h"
#include "AppFrame.h"
#include <iostream>
IMPLEMENT_APP( SimpleAuiApp )
SimpleAuiApp::SimpleAuiApp( )
{
}
SimpleAuiApp::~SimpleAuiApp( )
{
}
bool SimpleAuiApp::OnInit( )
{
// Open a console window for errors and standard output
AllocConsole( );
freopen( "CONOUT$", "wb", stdout );
freopen( "CONOUT$", "wb", stderr );
std::cout << "Initialization started...\n";
// Create the main application frame
m_AppData.m_pFrame = new AppFrame( (wxWindow*) NULL, &m_AppData );
// Bring the frame to the front
SetTopWindow( m_AppData.m_pFrame );
// See if a fixed frame rate is specified
if ( m_AppData.m_nDisplayUpdateRate > 0 )
{
// Start a timer to update the display at a fixed frame rate.
// Note that rate is increased by 10% to make up for wxWidget's inaccurate timers.
m_AppData.m_pTimer = new wxTimer( this );
float fMilliSeconds = 1000.0 / ( m_AppData.m_nDisplayUpdateRate * 1.1f );
m_AppData.m_pTimer->Start( fMilliSeconds );
Bind( wxEVT_TIMER, &SimpleAuiApp::OnTimer, this );
}
else
{
// capture the "on idle" event when not running at a fixed frame rate
Bind( wxEVT_IDLE, &SimpleAuiApp::OnIdle, this );
}
std::cout << "Initialization completed...\n";
return true;
}
// -------------------------------------------------------------
// Framerate - functions bound to framerate related events.
// Either OnTimer() or OnIdle() should be called here for each
// frame, but never both. They are two different refresh
// methods.
// -------------------------------------------------------------
// Called by widget app code on timer event
void SimpleAuiApp::OnTimer( wxTimerEvent& event )
{
std::cout << "Called SimpleAuiApp::OnTimer \n";
// update the frame's display
m_AppData.m_pFrame->UpdateDisplay( );
}
// -------------------------------------------------------------
// OnExit - Called by widget app code on shutdown
// -------------------------------------------------------------
int SimpleAuiApp::OnExit( )
{
// stop (and delete) the update timer if needed
if ( m_AppData.m_pTimer )
{
m_AppData.m_pTimer->Stop( );
delete m_AppData.m_pTimer;
m_AppData.m_pTimer = NULL;
}
// close the console window if needed
FreeConsole( );
// exit successful
return 0;
}
The problem ended up being that the AUI manager which you attach to the main Frame DOES consume the wxEVT_PAINT event when it propagates, and it never reaches the Frame's class. The Frame's children however, do receive the events.
Instead of just using Bind() from the Frame class, I called m_panelgl->Bind where the m_panelgl was my child container which held the OpenGL canvas.
this is my first experience,so don't be picky.
It's SIGSEGV problem, and it appears only in class linking.
The problem within "SDL_surface *ScreenSurface" pointer.
Here goes the code...
Screen header
class screen
{
public:
screen();
SDLclass_Window *MainWindow=NULL;
SDL_Surface *ScreenSurface=NULL; //this is the problem pointer to the struct that cause error
//Those pointer are't NULL, see below
virtual ~screen();
protected:
private:
const int SCREEN_WIDTH = 1280;
const int SCREEN_HEIGHT = 726;
bool init();
};
Screen code
screen::screen()
{
if(!init())
{
std::cout<<"ERROR at INIT";
SDL_Delay( 4000 );
}
else
{
bool quit=0;
SDL_Event e;
while (!quit)
{
SDL_UpdateWindowSurface(MainWindow);
//Looking for events
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
}
}
}
this->~screen();
}
bool screen::init() //Initialization
{
bool succses=1;
if (SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
std::cout<< "SDL could not initialize! SDL_Error:"<< SDL_GetError()<<std::endl;
succses=0;
return succses;
}
MainWindow= SDL_CreateWindow( "Arachy: WIP Version", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN ); //Setting parameters to SDL_window
if (MainWindow==NULL)
{
std::cout<<"can't create window"<<SDL_GetError()<<std::endl;
succses=0;
return succses;
}
else
{
//Get window surface
ScreenSurface = SDL_GetWindowSurface( MainWindow );// telling ScreenSurface that it our main screen surface
}
return succses;
}
screen::~screen()
{
SDL_Quit();
}
Activity header
(another class that uses SDL_Surface which defined above in class Screen)
class activity
{
public:
activity();
virtual ~activity();
protected:
private:
screen mainScreen;
void load();
};
Activity code (I'm trying to modify SDL_Surface with SDL_FillRect() after that i got SIGSEGV signal during debug
activity::activity()
{
SDL_FillRect(mainScreen.ScreenSurface,NULL,SDL_MapRGB(mainScreen.ScreenSurface->format,255,000000,255));
}
Please , help me to find out...
Thank you
The problem is twofold:
A) It's likely that the destructor of screen is called twice, causing SDL_DestroyWindow() and SDL_FreeSurface() to be called on invalid, non-NULL pointers.
If you absolutely, positively want to call your destructor twice, you should at least reset these pointers to NULL after destroying the objects they point to.
But in most cases you should simply, you know, not explicitly call the destructor...
B) As set now, activity's constructor body will never be called until the main event loop is over.
I'm trying to add an info bar to a dialog when my program is not connected to the databse. The info bar shows, however, if I close the dialog and open it again, every time there is a new button. Here's my code:
Window.hpp
class Window: public Gtk::Window {
private:
/// more things
Gtk::InfoBar info;
Gtk::Container* infoBarContainer;
Gtk::Label info_label;
protected:
void onConnectedBody(void);
void onNotConnectedBody(void);
void onInfoBarResponse(int response);
void onMenuDbConnect(void);
void onMenuDbDisconnect(void);
public:
/// more things...
};
Window.cpp
Window::Window(
) :
infoBarContainer(0),
info_label("")
{
// more things
info.add_button(Gtk::Stock::OK, 0);
infoBarContainer = dynamic_cast<Gtk::Container*>(info.get_content_area());
if( infoBarContainer ) infoBarContainer->add(info_label);
}
Window::onMenuDbConnect(){
if( controller->Connected() ) {
onConnectedBody();
} else {
onNotConnectedBody();
}
}
Window::onConnectedBody(){
Gtk::Dialog dialog("Connected to database",true,true);
dialog.set_resizable( false );
dialog.set_has_separator(true);
Gtk::Button close;
Gtk::VBox* vbox = dialog.get_vbox();
Gtk::Label label;
label.set_markup("<b>Already connected.</b>");
vbox->pack_start(label,false,false);
close.set_label("Close");
close.signal_clicked().connect(sigc::mem_fun(*this,&Window::onButtonClose));
dialog.set_size_request(250,80);
vbox = 0;
close.set_can_default( true );
dialog.add_action_widget(close,1);
close.grab_default();
dialog.show_all_children();
dialog.run();
}
Window::onNotConnectedBody(){
Gtk::Dialog dialog("Connect to database",true,true);
dialog.set_resizable( false );
dialog.set_has_separator(true);
Gtk::Button close;
Gtk::VBox* b = dialog.get_vbox();
info.signal_response().connect(sigc::mem_fun(*this,&Window::onInfoBarResponse) );
info_label.set_text("Remember to fill all fields");
b->pack_start(info,Gtk::PACK_SHRINK);
Gtk::Label label;
label.set_markup("<b>Database:</b>");
Gtk::Label label_host;
label_host.set_markup("<b>Host:</b>");
Gtk::Label label_user;
label_user.set_markup("<b>User:</b>");
Gtk::Label label_pass;
label_pass.set_markup("<b>Pass:</b>");
label.set_justify(Gtk::JUSTIFY_LEFT);
label_host.set_justify(Gtk::JUSTIFY_LEFT);
label_user.set_justify(Gtk::JUSTIFY_LEFT);
label_pass.set_justify(Gtk::JUSTIFY_LEFT);
entry.set_max_length(10);
entry.set_text("Figures");
entry_host.set_text("localhost");
label.set_markup("<b>Database:</b>");
b->pack_start(label,false,false);
b->pack_start(entry,false,false);
b->pack_start(label_host,false,false);
b->pack_start(entry_host,false,false);
b->pack_start(label_user,false,false);
b->pack_start(entry_user,false,false);
b->pack_start(label_pass,false,false);
b->pack_start(entry_pass,false,false);
close.set_label("Connect");
close.signal_clicked().connect(sigc::mem_fun(*this,&Window::onButtonDbConnect));
close.set_can_default( true );
dialog.add_action_widget(close,1);
close.grab_default();
dialog.set_size_request(250,250);
dialog.show_all_children();
dialog.run();
}
void Window::onInfoBarResponse(int response) {
info.hide();
}
So, what I want is to show the info bar whenever I enter the onMenuDbConnect and is not yet connected to the database. If it is connected, no info bar is shown. The other components of my program, like the DB controller, works perfectly.
Any ideas? Thaanks.
I have some weird behaviour in Qt that seems like a defect. I'd like to know if anybody has a good workaround.
I have a popup widget that contains many buttons in it. The user activates the popup by pressing the mouse button down. The popup widget calls grabMouse when shown. It gets all the mouse events. As it rolls over a button it calls setDown(true) on the button. Now however, when the mouse button is released the popup widget does not get the mouseReleaseEvent, that goes to the button.
That is, calling setDown(true) on a button causes the button to steal mouse events, bypassing the grabMouse in the popup widget.
I've looked at the source code for setDown but I can't see anything there that would do it directly. I also notice however that sometimes a button gets a hover event, sometimes not. I would assume it would never get those events when the mouse is grabbed.
//g++ -o grab_lost grab_lost.cpp -lQtCore -lQtGui -I /usr/include/qt4/ -I /usr/include/qt4/QtCore -I /usr/include/qt4/QtGui
/**
Demonstrates the defect of losing the mouse. Run the program and:
1. Press mouse anywhere
2. release in purple block (not on X)
3. Release message written (GrabLost receives the mouseReleaseEvent)
For defect:
1. Pree mouse anywhere
2. Release inside the X button
3. button is clicked, no release message (GrabLost does not get the mouseReleaseEvent)
*/
#include <QWidget>
#include <QPushButton>
#include <QApplication>
#include <QMouseEvent>
#include <QPainter>
class GrabLost : public QWidget
{
QPushButton * btn;
public:
GrabLost( QWidget * parent = 0)
: QWidget( parent, Qt::Popup )
{
btn = new QPushButton( "X", this );
setMouseTracking( true );
}
protected:
void showEvent( QShowEvent * ev )
{
QWidget::showEvent( ev );
grabMouse();
}
void closeEvent( QCloseEvent * ev )
{
releaseMouse();
QWidget::closeEvent( ev );
}
void hideEvent( QHideEvent * ev )
{
releaseMouse();
QWidget::hideEvent( ev );
}
void mouseReleaseEvent( QMouseEvent * ev )
{
qDebug( "mouseRelease" );
close();
}
void mouseMoveEvent( QMouseEvent * ev )
{
QWidget * w = childAt( ev->pos() );
bool ours = dynamic_cast<QPushButton*>( w ) == btn;
btn->setDown( ours );
}
void paintEvent( QPaintEvent * ev )
{
//just to show where the widget is
QPainter pt( this );
pt.setPen( QColor( 0,0,0 ) );
pt.setBrush( QColor( 128,0,128) );
pt.drawRect( 0, 0, size().width(), size().height() );
}
};
class GrabMe : public QWidget
{
protected:
void mousePressEvent( QMouseEvent * ev )
{
GrabLost * gl = new GrabLost();
gl->resize( 100, 100 );
QPoint at( mapToGlobal( ev->pos() ) );
gl->move( at.x() - 50, at.y() - 50 );
gl->show();
}
};
int main( int argc, char** argv )
{
QApplication app( argc, argv );
GrabMe * gm = new GrabMe();
gm->move( 100, 100 );
gm->resize( 300, 300 );
gm->show();
app.exec();
return 0;
}
I've entered the defect at the Nokia DB. I'm giving it about a 95% chance that they close it as "works as intended".
For those of you that need a solution nonetheless you'll have to use event filters and create your own grabbing. Basically install an event filter for every child widget and propagate the mouse events to the parent.
Note in the above code that the right mouse button doesn't work even if you don't call setDown.
Say there is a QPushButton named "Draw", a QLineEdit and a QFrame. On clicking the button I want to take a number from QLineEdit and draw a circle in a QFrame. How can I do this? Please provide me with the code.
P.S. The problem is that draw methods of the QPainter should be called in drawEvent method.
If #Kaleb Pederson's answer is not enough for you then here's a complete solution for a simple set-up matching what you describe. Tested with Qt 4.5.2 on Linux. I had some spare time... ;)
main.cpp:
#include <QApplication>
#include "window.h"
int main( int argc, char** argv )
{
QApplication qapp( argc, argv );
Window w;
w.show();
return qapp.exec();
}
window.h
#pragma once
class QLineEdit;
class QPushButton;
#include <QWidget>
class Frame;
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private slots:
void onButtonClicked();
private:
QLineEdit* m_lineEdit;
QPushButton* m_pushButton;
Frame* m_frame;
};
window.cpp:
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include "frame.h"
#include "window.h"
Window::Window()
: m_lineEdit ( new QLineEdit( this ) )
, m_pushButton( new QPushButton( tr( "Draw" ), this ) )
, m_frame ( new Frame( this ) )
{
connect( m_pushButton, SIGNAL( clicked() )
, SLOT( onButtonClicked() ) );
QHBoxLayout*const hLayout = new QHBoxLayout;
hLayout->addWidget( m_lineEdit );
hLayout->addWidget( m_pushButton );
QVBoxLayout*const vLayout = new QVBoxLayout( this );
vLayout->addLayout( hLayout );
m_frame->setFixedSize( 300, 400 );
vLayout->addWidget( m_frame );
setLayout( vLayout );
}
void Window::onButtonClicked()
{
const int r = m_lineEdit->text().toInt(); // r == 0 if invalid
m_frame->setCircleRadius( r );
m_frame->update();
}
frame.h:
#pragma once
#include <QFrame>
class Frame : public QFrame
{
Q_OBJECT
public:
Frame( QWidget* );
void setCircleRadius( int );
protected:
void paintEvent( QPaintEvent* );
private:
int m_radius;
};
frame.cpp:
#include <QPainter>
#include "frame.h"
Frame::Frame( QWidget* parent )
: QFrame( parent )
, m_radius( 0 )
{
setFrameStyle( QFrame::Box );
}
void Frame::setCircleRadius( int radius )
{
m_radius = radius;
}
void Frame::paintEvent( QPaintEvent* pe )
{
QFrame::paintEvent( pe );
if ( m_radius > 0 )
{
QPainter p( this );
p.drawEllipse( rect().center(), m_radius, m_radius );
}
}
If you want your frame to do the drawing, then it needs a way to know that it should draw something, so create a slot that will receive notification:
/* slot */ void drawCircle(QPoint origin, int radius) {
addCircle(origin, radius);
update(); // update the UI
}
void addCircle(QPoint origin, int radius) {
circleList.add(new Circle(origin,radius));
}
Then, your frame subclass you need to override paintEvent() to draw the circle:
void paintEvent(QPaintEvent *event) {
QFrame::paintEvent(event);
QPainter painter(this);
foreach (Circle c, circleList) { // understand foreach requirements
painter.drawEllipse(c.origin(), c.radius(), c.radius());
}
}
As long as the slot responding to the button's clicked() signal emits a signal that calls the drawCircle slot with the correct arguments everything should work correctly.
You don't draw diectly onto a frame.
Start here graphicsview, it looks complicated at first - but GUI program is a big leap when you first encounter it
In most GUIs (Qt, OpenGL etc) you build up a list of elements you want to draw in your program and store them somehow - then there is a draw() function that gets called when the computer needs to draw your picture - eg when it is moved or another window is moved in front of it. The OnDraw or OnRepaint etc function then gets called and you have to draw the list of objects.
Another way to do this is to draw them all to an image (QOimage or QPixmap) and copy that to the screen in OnDraw or OnRepaint - you might do this for a graphics package for example.