Em interface gráfica do usuário (GUI), uma interface de documentos múltiplos, ou MDI, acrônimo para Multiple Document Interface é um método de organização de aplicações gráficas em janelas que residem em uma única janela, a janela principal da aplicação. A única exceção são possíveis janelas modais da aplicação.

Com múltiplas interfaces de documentos, uma única barra de menu e / ou barra de ferramentas é compartilhado entre todas as janelas filho, reduzindo a desordem e uma utilização mais eficiente do espaço na tela. As janelas filho de um aplicativo pode ser ocultada / mostrada / minimizada / maximizada como um todo. Os autores de aplicações multi-plataforma podem fornecer a seus usuários um comportamento consistente da aplicação entre plataformas.

Interface de Múltiplos Documentos

Interface de Múltiplos Documentos

MdiClient

Representa o recipiente para uma interface de documentos múltiplos (MDI) formulários filho. Você definir se um formulário será um container para múltiplos documentos através da propriedade Form.IsMdiContainer.

Form Child

Você pode definir um formulário como filho o atribuindo a um formulário pai através da propriedade MdiParent, que 0btém ou define uma interface de documentos múltiplos.

Exemplo:

Neste exemplo criamos um formulário MDI básico e um menu. Ressaltando que usamos o Design Time do Visual Studio somente para criar os formulários por opção, o código é inserido parte no construtor da classe do formulário e parte no evento OnShown do Form. Você pode criar tudo dinamicamente ou tudo em Design Time. Vale brincar com o construtor e os eventos dos formulários, porque apesar de alguns eventos possuírem funcionalidades parecidas, não são iguais e existem diferenças peculiares entre eles.

Para criar o segundo formulário, clique com o botão direito em cima do seu projeto na janela Solution Explorer e clique em Add e em Windows Form.

C#

Formulario – Pai

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace formularioMdi
{
    public partial class Form1 : Form
    {
        // Declara componentes
        MenuStrip menu;

        public Form1()
        {
            // Inicializa formulario       
            
            // Define formulario como pai.
            this.IsMdiContainer = true;
                        
            // Cria painel para formularios filhos
            ToolStripPanel painel = new ToolStripPanel();

            // Define tamanho do painel
            painel.Dock = DockStyle.Fill;

            // Cria barra do menu
            menu = new MenuStrip();

            // Cria menu
            ToolStripMenuItem itens1 = new ToolStripMenuItem("Formularios");

            // Cria itens do menu
            ToolStripMenuItem m1item1 = new ToolStripMenuItem("Novo", null, new EventHandler(clique1_m1));
            ToolStripMenuItem m1item2 = new ToolStripMenuItem("Sair", null, new EventHandler(clique2_m1));

            // Adiciona itens ao menu e menu a barra de menu
            itens1.DropDownItems.Add(m1item1);
            itens1.DropDownItems.Add(m1item2);
            menu.Items.Add(itens1);            

            InitializeComponent();
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            // Define texto 
            this.Text = "Desenvolvimento Aberto - Formulario - Main Form / Child Form";

            // Define tamanho e posição do formulario principal            
            this.Top = 0;
            this.Left = 0;
            this.Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width - 50;
            this.Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height - 50;
           
            // Adiciona menu ao formulario
            this.Controls.Add(menu);

        }

        private void clique1_m1(object sender, EventArgs e)
        {
            // Chama instancia do formulario filho
            FormularioFilho formularioFilho = new FormularioFilho();
            formularioFilho.MdiParent = this;
            
            // Usa metodo estatico para exibir numero da instancia
            formularioFilho.Text = "Formulario Filho - Instancia:" + this.MdiChildren.Length.ToString();

            // Chama formulario
            formularioFilho.Show();
        }

        private void clique2_m1(object sender, EventArgs e)
        {
            // Fecha formulario
            this.Close();
        }

    }
}

Formulario – Filho

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace formularioMdi
{
    public partial class FormularioFilho : Form
    {
        // Declara componentes
        Label rotulo;
        TextBox campo;
        Button botao;

        public FormularioFilho()
        {
            InitializeComponent();
        }

        private void FormularioChild_Shown(object sender, EventArgs e)
        {
            // Define tamanho do formulario
            this.Size = new Size(360, 150);

            // Cria componentes
            rotulo = new Label();
            campo = new TextBox();
            botao = new Button();

            // Defie tamanho
            rotulo.Size = new Size(200, 20);
            campo.Size = new Size(300, 20);

            // Define posição
            rotulo.Location = new Point(12, 20);
            campo.Location = new Point(12, 40);
            botao.Location = new Point(12, 70);

            // Define texto
            rotulo.Text = "Digite seu nome:";
            botao.Text = "Ok";

            // Adiciona componentes ao fomrulario
            this.Controls.Add(rotulo);
            this.Controls.Add(campo);
            this.Controls.Add(botao);

        }
    }
}

 

 

Em interface gráfica do usuário (GUI), uma interface de documentos múltiplos, ou MDI, acrônimo para Multiple Document Interface é um método de organização de aplicações gráficas em janelas que residem em uma única janela, a janela principal da aplicação. A única exceção são possíveis janelas modais da aplicação.

Com múltiplas interfaces de documentos, uma única barra de menu e / ou barra de ferramentas é compartilhado entre todas as janelas filho, reduzindo a desordem e uma utilização mais eficiente do espaço na tela. As janelas filho de um aplicativo pode ser ocultada / mostrada / minimizada / maximizada como um todo. Os autores de aplicações multi-plataforma podem fornecer a seus usuários um comportamento consistente da aplicação entre plataformas.

Interface de Múltiplos Documentos

Interface de Múltiplos Documentos

JDesktopPane

É um recipiente utilizado para criar uma interface de documentos múltiplos ou uma área de trabalho virtual. Você cria objetos JInternalFrame e adicioná-los ao JDesktopPane. A classe JDesktopPane estende o  JLayeredPane para gerenciar os quadros internos potencialmente sobrepostos. Ele também mantém uma referência a uma instância de DesktopManager que é definido pela classe UI para o Look and Feel da aplicação.

JInternalFrame

Um objeto leve que fornece muitas das características de uma estrutura nativa, incluindo arrastar, fechar, mostrar um ícone, redimensionar, exibir títulos, e também possui suporte para uma barra de menus.

Exemplo:

Neste exemplo criamos um formulário MDI básico e um menu.

Java

Classe – Janela Pai


import javax.swing.JDesktopPane;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JFrame;
import javax.swing.KeyStroke;

import java.awt.event.*;
import java.awt.*;


public class FormularioMdi extends JFrame implements ActionListener
{
	// Declara componetes
    JDesktopPane painel;

    public FormularioMdi() 
    {
    	// herda classe
    	super("Java - Formularios - MDI - JFrame / JDesktopPane / JInternalFrame");
        
    	// Define tamanho da janela principal
        int bordas = 50;
        Dimension tela = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(bordas, bordas, tela.width  - bordas *2 , tela.height - bordas *2);
        
        // Cria painel principal
        painel = new JDesktopPane(); 
        painel.setBackground(Color.LIGHT_GRAY);
                
        setContentPane(painel);
        setJMenuBar(createMenuBar());        
    }

    protected JMenuBar createMenuBar()
    {
    	// Cria barra de menu
        JMenuBar barra = new JMenuBar();
        
        // Cria menu
        JMenu menu = new JMenu("Formularios");        
        barra.add(menu);

        // Cria itens dos menus
        JMenuItem item = new JMenuItem("Novo");
        item.setActionCommand("novo");
        item.addActionListener(this);
        menu.add(item);

        //Cria segundo item
        item = new JMenuItem("Sair");
        item.setActionCommand("sair");
        item.addActionListener(this);
        menu.add(item);

        return barra;
    }

    
    public void actionPerformed(ActionEvent e) 
    {
    	// Cria eventos do menu
        if (e.getActionCommand() == "novo")
        { 
            criaFormulario();
        } 
        else 
        {
            sair();
        }
    }

    protected void sair() 
    {
    	// Fecha sistema
        System.exit(0);
    }
    
    protected void criaFormulario()
    {
    	// Cria formulario filho
    	FormularioFilho frame = new FormularioFilho();
        frame.setVisible(true); 
        
        // Adiciona janela filho na janela pai
        painel.add(frame);
        try 
        {
        	// Seta foco
            frame.setSelected(true);
        }
        catch (java.beans.PropertyVetoException e)        
        {
        	
        }
    }
       
    
    private static void criaGUI() 
    {     
    	// Decora barra da janela
    	JFrame.setDefaultLookAndFeelDecorated(true);

    	// Cria formulario filho     
        FormularioMdi formulario = new FormularioMdi();
        formulario.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
        // Exibe formulario
        formulario.setVisible(true);
    }

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable()
        {
            public void run() 
            {
            	// Chama GUI
                criaGUI();
            }
        });
    }
}

Classe – Janela Filho

import java.awt.Container;
import java.awt.Dimension;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class FormularioFilho extends JInternalFrame
{   
	// Declara componentes
	JLabel rotulo;
	JTextField campo;
	JButton botao;
	
	// Declara variaveis
	static int formulario = 0;
    static int posicao = 30;
    
    public FormularioFilho()
    {    	
    	// Herda da classe filho
    	super("Formulario Filho - Instancia :" + (++formulario), true, true, true, true);

    	// Cria painel
        setContentPane(criaPainel());
    	pack();
        
    	// Define posição do formulario
        setLocation(posicao * formulario, posicao * formulario);        
        
    }
    
    public Container criaPainel()
    {
    	// Cria painel
    	JPanel painel = new JPanel(); 
    	
    	// Define layout
    	painel.setLayout(new BoxLayout(painel, BoxLayout.PAGE_AXIS));
		painel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
		
		// Cria componentes
		rotulo = new JLabel("Digite Seu nome:");
		campo = new JTextField();
		botao = new JButton("Ok");
		
		// define tamanho do campo
		campo.setPreferredSize(new Dimension(300,20));
		
		// Adiciona componentes ao painel	
		painel.add(rotulo);		
		painel.add(Box.createVerticalStrut(10));
		painel.add(campo);
		painel.add(Box.createVerticalStrut(20));
		painel.add(botao);
    	
    	return painel;
    }
    
    private static void criaGUI() 
    {
    	// Cria GUI (Janela Filho)
        JFrame.setDefaultLookAndFeelDecorated(true);
     
        FormularioMdi formulario = new FormularioMdi();
        formulario.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
        // Exibe formulario
        formulario.setVisible(true);
    }

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable()
        {
            public void run() 
            {
            	// Chama GUI
                criaGUI();
            }
        });
    }
}

O primeiro passo para uma boa gestão objetos JavaScript está em ter um espaço de nomes, ou um objeto JavaScript que contém o nosso código, que você sabe que não vai entrar em conflito com o código do Firefox ou outras extensões. Declaração de namespace é melhor localizado em um arquivo próprio.

Por convenção, o nome de um módulo deve corresponder a seu namespace. O módulo desenvolvimentoaberto deve ser armazenado num ficheiro chamado desenvolvimentoaberto.js.

namespace-js

Namespace – Javascript

 

Exemplo:

Neste exemplo criamos um namespace que pode conter uma coleção de objetos.

Html / JavaScript

<!DOCTYPE html>
<html>

<head>
   <title>Desenvolvimento Aberto</title>
</head>

<body>

<h2>Desenvolvimento Aberto</h2>
<h3>Javascript Orientado a Objeto - Namespace</h3>
<h4>JavaScript</h4>
<br>

<pre>
<script>

// Declara namespace
var desenvolvimento; 

// Iniacializa namespace
if (!desenvolvimento) desenvolvimento = {};

//   Cria namespace
desenvolvimento.aberto = {};

//  Adiciona metodos
desenvolvimento.aberto.soma = function (x, y) { return x + y };
desenvolvimento.aberto.subt = function (x, y) { return x - y };

//  Cria Alias
var das = desenvolvimento.aberto.soma;
var dat = desenvolvimento.aberto.subt;

// Escreve no documento html    

document.writeln("O Namespace desenvolvimento.aberto contem:") 

document.writeln("\nSoma: 30 + 20 = " +  desenvolvimento.aberto.soma(30, 20));

document.writeln("Alias - Soma = " + das(30, 20));

document.writeln("\nSubtrai: 30 - 20 = " +  desenvolvimento.aberto.subt(30, 20));

document.writeln("Alias - Subtrai = " + dat(30, 20));

</script>
</pre>

</body>

</html>

Visual – ToolTip e cl_salv_tooltips – Abap

Publicado: 30 de abril de 2014 em Abap

Tooltip é um elemento comum de interface gráfica GUI, também conhecida como dica de contexto é aquela moldura pop up que abre quando você passa o mouse sobre um elemento da interface (normalmente uma palavra em um texto) e que contém uma explicação adicional sobre aquele elemento que recebeu o ponteiro do mouse sobre ele. É utilizado em conjunto com um cursor, normalmente um ponteiro do mouse. O usuário paira o cursor sobre um item, sem clicar nele, e uma pequena “caixa” irá aparece com informações complementares relativas a este item.

ToolTip - Screen Painter

ToolTip – Screen Painter

ToolTip

Para utilizar o tooltip no Screen Painter basta preencher a propriedade do componente com a dica requerida.

cl_salv_tooltips

O objeto de dica de ferramenta contém as seguintes informações: o tipo de dica de objeto que é para qual elemento a dica pode ser processada, o indicador para o elemento e o texto que é apresentado como dica.

Para um exemplo desta classe utilize o programa de exemplo do Netweaver: BCALV_DEMO_TOOLTIP.

Mais informações sobre tooltips: http://help.sap.com/saphelp_nw70/helpdata/en/1f/6dee408a63732ae10000000a155106/content.htm?frameset=/en/1f/6dee408a63732ae10000000a155106/frameset.htm

Exemplo:

Neste exemplo usamos a propriedade tooltip do elemento PushButton do Screen Painter, para usar o programa abaixo crie uma tela, um evento PBO e o campo OK_CODE e preencha o campo function code para o botão como F_BTN1,  para exemplo da classe use o programa citado. acima.

Abap

*&---------------------------------------------------------------------*
*& Report  ZTOOLTIP
*&
*&---------------------------------------------------------------------*
*& Desenvolvimento Aberto
*& ToolTip
*&---------------------------------------------------------------------*

REPORT  ZTOOLTIP.

DATA: ok_code LIKE sy-ucomm,
      clique_ok LIKE sy-ucomm.

CALL SCREEN 100.

MODULE STATUS_0100 OUTPUT.
*  SET PF-STATUS 'xxxxxxxx'.
*  SET TITLEBAR 'xxx'.

* limpa evento
  clique_ok = ok_code.
  CLEAR ok_code.

* Eventos dos botões ou teclas
  CASE clique_ok.

    WHEN 'F_BTN1'.
      LEAVE PROGRAM.

  ENDCASE.

ENDMODULE.                 " STATUS_0100  OUTPUT

 

Tooltip é um elemento comum de interface gráfica GUI, também conhecida como dica de contexto é aquela moldura pop up que abre quando você passa o mouse sobre um elemento da interface (normalmente uma palavra em um texto) e que contém uma explicação adicional sobre aquele elemento que recebeu o ponteiro do mouse sobre ele. É utilizado em conjunto com um cursor, normalmente um ponteiro do mouse. O usuário paira o cursor sobre um item, sem clicar nele, e uma pequena “caixa” irá aparece com informações complementares relativas a este item.

ToolTip - Tkinter

ToolTip – Tkinter

ToolTip

A classe ToolTip fornece um widget de dica flexível para Tkinter.

Download

http://tkinter.unpythonic.net/wiki/ToolTip

Exemplo:

Neste exemplo utilizaremos uma classe de fonte aberto para criar um Widget ToolTip, salve a classe no diretório de sua aplicação ou nos diretórios do Python.

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Desenvolvimento Aberto
# ToolTip.py

# importa modulos
import Tkinter
from ToolTip import ToolTip

# Cria formulario
formulario = Tkinter.Tk(className='Tk - ToolTip')

# Cria componentes
rotulo = Tkinter.Label(formulario, text="Pare o cursor em cima do Button por alguns segundos")

botao = Tkinter.Button(formulario, text='Aperte Aqui !!!', command=formulario.quit)

# Cria Dica (Tooltip)
dica = ToolTip(botao, follow_mouse=1, text="Desenvolvimento Aberto, Clique para sair do programa.")

# Posiciona componentes
rotulo.pack(padx=20, pady=10)
botao.pack(pady=10)

# Loop do Tcl
formulario.mainloop()

Tooltip é um elemento comum de interface gráfica GUI, também conhecida como dica de contexto é aquela moldura pop up que abre quando você passa o mouse sobre um elemento da interface (normalmente uma palavra em um texto) e que contém uma explicação adicional sobre aquele elemento que recebeu o ponteiro do mouse sobre ele. É utilizado em conjunto com um cursor, normalmente um ponteiro do mouse. O usuário paira o cursor sobre um item, sem clicar nele, e uma pequena “caixa” irá aparece com informações complementares relativas a este item.

CToolTipCtrl

CToolTipCtrl

CToolTipCtrl

Encapsula a funcionalidade de um controle dica de ferramenta“, uma pequena janela pop-up que exibe uma única linha de texto que descreve a finalidade de uma ferramenta em um aplicativo.

PreTranslateMessage

Você pode efetuar um método Override para substituir esta função para filtrar mensagens de janela antes de serem enviados para Windows.

Visual Studio

Para criar um controle ToolTip para um dialogo MFC em C++ siga os seguintes passos:

  1. Crie um novo projeto MFC Dialog Based.
  2. Coloque no dialogo um componente Static Text e um componente Button, crie uma variável para o botão chamada m_botao.
  3. Disponha os componentes no dialogo conforme a imagem abaixo:

    CToolTipCtrl - Design

    CToolTipCtrl – Design

  4. Declare o método Override para a mensagem PreTranslateMessage e crie um objeto CToolTipCtrl para a classe de seu dialogo, use o primeiro código para se basear.
  5. Complete seu código gerado automaticamente para a implementação da classe, use o segundo código para se basear.

Exemplo:

Neste exemplo usamos o objeto CToolTipCtrl para exibir uma dica para o usuário ao pairar o cursor do mouse sobre o botão, interceptando a mensagem e exibindo o texto da dica na mensagem do Windows PreTranslateMessage.

C++

Classe – Definição (.h)


// tooltipcppDlg.h : header file
//

#pragma once
#include "afxwin.h"

class CtooltipcppDlg : public CDialogEx
{

public:
	CtooltipcppDlg(CWnd* pParent = NULL);	

	enum { IDD = IDD_TOOLTIPCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);

protected:
	HICON m_hIcon;

	// Desenvolvimento Aberto
	// Declara metodo de menssagem
	BOOL PreTranslateMessage(MSG* pMsg);
	
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Declara componente tooltip
	CToolTipCtrl* m_pToolTip;

	CButton m_botao;
};

Classe – Implementação (.cpp)


// tooltipcppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "tooltipcpp.h"
#include "tooltipcppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CtooltipcppDlg::CtooltipcppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CtooltipcppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CtooltipcppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_BUTTON1, m_botao);
}

BEGIN_MESSAGE_MAP(CtooltipcppDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()


BOOL CtooltipcppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
		
	SetIcon(m_hIcon, TRUE);			
	SetIcon(m_hIcon, FALSE);		

	// Desenvolvimento Aberto
	// Inicializa objeto tooltip e define suas propriedades	
	
	// Cria objeto tooltip 
	m_pToolTip = new CToolTipCtrl;

	if (!m_pToolTip->Create(this))
	{	
		return TRUE;
	}

	// Define objeto para a dica
	m_pToolTip->AddTool(&m_botao, 
		L"Desenvolvimento Aberto - Clique neste botão para executar uma ação.");
	
	// Ativa tooltip
	m_pToolTip->Activate(TRUE);

	return TRUE;  
}

void CtooltipcppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
				
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;
				
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CtooltipcppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// Desenvolvimento Aberto
// Cria override da menssagem do windows

BOOL CtooltipcppDlg::PreTranslateMessage(MSG* pMsg)
{
	m_pToolTip->RelayEvent(pMsg);

	return CDialog::PreTranslateMessage(pMsg);
}

Visual – ToolTip – C#

Publicado: 29 de abril de 2014 em C#

Tooltip é um elemento comum de interface gráfica GUI, também conhecida como dica de contexto é aquela moldura pop up que abre quando você passa o mouse sobre um elemento da interface (normalmente uma palavra em um texto) e que contém uma explicação adicional sobre aquele elemento que recebeu o ponteiro do mouse sobre ele. É utilizado em conjunto com um cursor, normalmente um ponteiro do mouse. O usuário paira o cursor sobre um item, sem clicar nele, e uma pequena “caixa” irá aparece com informações complementares relativas a este item.

ToolTip

ToolTip

ToolTip

Representa uma pequena janela pop-up retangular que exibe uma breve descrição do propósito de um controle quando o usuário posicionar o ponteiro do mouse sobre o controle.

Exemplo:

Neste exemplo usamos o objeto ToolTip para exibir uma dica para o usuário ao pairar o cursor do mouse sobre o botão.

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Dicas
{
    public partial class Form1 : Form
    {
        // Declara componentes
        Label rotulo;
        Button botao;
        ToolTip dicas;
                
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            // Define propriedades do formulario
            this.Text = "DA - ToolTip";
            this.Size = new Size(300, 150);

            // Cria componentes
            rotulo = new Label();
            botao = new Button();
            dicas = new ToolTip();

            // Define tamanho e localização
            rotulo.Size = new Size(300, 20);
            rotulo.Location = new Point(0, 20);
            botao.Location = new Point(10, 50);

            // Define textos
            rotulo.Text = "Pare o cursor em cima do botão por alguns segundos";
            botao.Text = "Aperte Aqui!";

            // Alinha texto
            rotulo.TextAlign = ContentAlignment.TopCenter;

            // Define propriedades de tempo para o componente de dicas
            dicas.AutomaticDelay = 2000;
            dicas.AutoPopDelay = 3000;
            dicas.ReshowDelay = 500;
            dicas.ShowAlways = true;

            // Define dica para o componente escolhido
            dicas.SetToolTip(botao, "Desenvolvimento Aberto - " +
                                    "Clique neste botão para executar uma ação.");

            // Adiciona componentes ao formulario
            this.Controls.Add(rotulo);
            this.Controls.Add(botao);

        }
       
    }
}

Visual – JToolTip – Java

Publicado: 29 de abril de 2014 em Java

Tooltip é um elemento comum de interface gráfica GUI, também conhecida como dica de contexto é aquela moldura pop up que abre quando você passa o mouse sobre um elemento da interface (normalmente uma palavra em um texto) e que contém uma explicação adicional sobre aquele elemento que recebeu o ponteiro do mouse sobre ele. É utilizado em conjunto com um cursor, normalmente um ponteiro do mouse. O usuário paira o cursor sobre um item, sem clicar nele, e uma pequena “caixa” irá aparece com informações complementares relativas a este item.

JToolTip

JToolTip

JToolTip

Usado para exibir uma dica” para um componente. Normalmente componentes fornecem api para automatizar o processo de utilização de dicas de ferramentas. Por exemplo, qualquer componente Swing pode usar o método JComponent setToolTipText para especificar o texto para uma dica de ferramenta padrão. Um componente que quer criar uma exibição personalizada dica de ferramenta pode substituir o método createToolTip de JComponent e usar uma subclasse dessa classe.

Exemplo:

Neste exemplo usamos o método setToolTipText para exibir uma dica para o usuário ao pairar o cursor do mouse sobre o botão.

Java

import java.awt.Container;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Dicas {

	// Declara componentes
	JLabel rotulo;
	JButton botao;

	// Declara variaveis
	String dica = "Desenvolvimento Aberto - " +
	              "Clique neste botão para executar uma ação.";			     

	public Container criaPainel()
	{
		// Cria painel
		JPanel painel = new JPanel();

		// Define layout
		painel.setLayout(new BoxLayout(painel, BoxLayout.PAGE_AXIS ));
		painel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
		painel.setOpaque(true);

		// Cria componentes
		rotulo = new JLabel("Pare o cursor em cima do botão por alguns segundos");
		botao  = new JButton("Aperte Aqui!");

		// Cria tooltip
		botao.setToolTipText(dica);

		// Adiciona componentes ao painel
		painel.add(rotulo);
		painel.add(Box.createVerticalStrut(10));
		painel.add(botao);

		return painel;
	}

	public static void criaGUI()
	{
		// Cria formulario
		JFrame formulario = new JFrame("DA - ToolTip");
		formulario.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// Cria instancia da classe
		Dicas dicas = new Dicas();

		// Define painel de conteudo
		formulario.setContentPane(dicas.criaPainel());

		// Define propriedades do formulario
		formulario.pack();
		formulario.setVisible(true);

	}

	public static void main(String[] args)
	{
		// Thread do swing
		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run()
			{
				// Mostra GUI
				criaGUI();
			}

		});

	}

}

O que a linguagem de programação Delphi tem em comum com Java e C#? A resposta é tudo? Ou nada? Quem sabe!. Estranho? Com certeza! E a resposta correta depende da versão do Delphi do qual estamos nos referindo. Ou não?

O Delphi nasceu em 1995 como uma linguagem de programação Object Pascal para o Windows 16 bits e foi o primeiro a ser descrito como ambiente RAD (em português, Desenvolvimento Rápido de Aplicações), seu nome faz alusão ao banco de dados Oracle, pois na mitologia grega o Oraculo (Oracle) podia ser encontrado no templo de Delphi.

Delphi - Win32

Delphi – Win32

O Delphi se difundiu pelo mundo na sua versão para Windows 32 bits,  justamente por fazer realmente o que prometia, era rápido para desenvolvimento em grandes equipes, podia se conectar com qualquer banco de dados e de vários modos diferentes, além de possuir uma gama de componentes de todos os tipos, desde os Open Source, como o famoso pacote de componentes Russo chamado RX, até componentes empresariais relacionado a dados e ao visual da aplicação como o InfoPower e 1st Class da empresa Woll2Woll.

O Delphi também possuía vários componentes para relatório onde podia-se  utilizar o poder da sua conexão com o banco de dados Oracle, unidos aos recursos de seus componentes, também possuía integração com o gerador de relatório mais famoso do mundo o Cristal Reports que hoje pertence a SAP.

Outro ponto forte do Delphi é que era possível programar rotinas em Assembler dentro do Object Pascal apenas abrindo um bloco ASM e dizendo direto ao hardware o que o desenvolvedor gostaria de fazer. O Delphi também possuía várias rotinas Assembler como parte de seus comandos como o caso do comando Abort, para ver estas rotinas bastava clicar em cima do comando em questão escrito de qualquer Unit pascal  e pressionando o botão Control (CTRL + Click)  e automaticamente você seria levado ao código que o originava, assim como nas IDEs de hoje em dia.

Assembler Delphi: http://docwiki.embarcadero.com/RADStudio/XE3/en/Using_Inline_Assembly_Code

Com o “Boom” do Linux em 2001 foi lançada uma versão para esta plataforma chamada Kylix,  com o lançamento do Delphi 8 a linguagem passou a suportar o .NET Framework, podendo-se escrever programas C# direto de sua IDE, mas não vingou e  muitas empresas estacionaram seu desenvolvimento na versão 7 do Delphi. O Delphi hoje é marca registrada da empresa Embarcadero e está na sua versão XE10 (emprestando a estratégia de versão do Windows 10) no qual pode-se desenvolver aplicações verdadeiramente nativas para Windows, Mac, Android e iOS a partir de uma única base de código.

Delphi 7 - Win32

Delphi 7 – Win32

Desenvolvimento em Delphi vale a pena migrar para Java ou C#?

Bom,  então, para quem migrou da versão 7 do Delphi para suas versões superiores e utilizou o suporte a plataforma .Net não temos muito o que falar, pois C# lembra muito o Java que por sua vez bebeu da fonte do C++ e assim por diante, mas para aqueles que continuam desenvolvendo em Delphi para Win32 a coisa é bem diferente.

Existe até uma URL estratégica da Embarcadero preparada para as pesquisas do Google:

UpGrade Delphi 7 para XE10: http://www.embarcadero.com/br/products/rad-studio/upgrade-from-delphi7

Programas escritos em Delphi 7, suas versões anteriores ou versões superiores mas utilizando projetos de código nativo ainda são comuns e a pergunta mais frequente é se vale a pena migrar para Java ou C#?

A resposta é simples, sim! Vale a pena mudar!

Por que ?

Ao contrario do que a maioria pensa (que me digam os proprietários de software houses que ainda desenvolve em Delphi código nativo)  desenvolver para Win32 exige um conhecimento muito técnico das APIs do Windows, apesar do Delphi transformar esta programação em uma tarefa extremamente fácil (vide Visual Studio MFC C++ para Win32) o resultado algumas vezes pode não ser aquele desejado pelos proprietários de software house, nem pelos clientes e nem pelos programadores.

Na pratica existem muitos programas escritos em Delphi para Win32 que são lentos, mesmo usando o melhor banco de dados do mundo, o Oracle, sem entrar no mérito das melhores praticas para um banco de dados. Muitos programas geram erros de memoria sozinhos, apenas com o usuário o utilizando, são difíceis de dar manutenção e não são projetados para o crescimento da base de dados, e pasmem, existem programas que param de funcionar devido a lentidão quando utilizados em bases de dados de grande porte (entrando no mérito das melhores praticas para um banco de dados), gerando para as empresas uma legião de clientes insatisfeitos, se identificou?

Mas o problema não é do Delphi e nem das APIs do Windows e sim da técnica dos programadores principalmente de programas que já foram migrados do Cobol, Clipper, DataFlex entre outras linguagens na qual se utiliza bases de dados relativamente grandes. Um erro comum era não conhecer o sistema operacional e não usar Dlls e ActiveX, criando Units de código pascal para as bibliotecas e programas reutilizáveis que eram referenciadas entre si e compiladas junto com o executável o tornando enorme, além disto, necessitando deste modo criar grande quantidade de procedimentos e funções publicas para estas Units ou Forms também referenciados (quando a convenção para qualquer linguagem orientada a objeto diz que você deve sempre criar métodos privados e usar métodos públicos somente quando realmente for necessário). A consequência deste tipo de programação é sem duvida, vazamento de memoria (Memory Leak), visto que apenas o Delphi com suporte ao .NET Framework possui o Garbage Collector, além de códigos fonte crescendo desordenadamente ao longo dos anos, sem contar outros inúmeros conceitos da programação para Win32 que continuaram sendo completamente ignorados.

Dinamic-Link Library: http://msdn.microsoft.com/en-us/library/windows/desktop/ms681914(v=vs.85).aspx

Component Object Model: http://msdn.microsoft.com/en-us/library/windows/desktop/ms694363(v=vs.85).aspx

Delphi ActiveX Framework: http://docwiki.embarcadero.com/RADStudio/XE3/en/Overview_of_COM_Technologies

Memory Leak Delphi: http://delphi.about.com/od/oopindelphi/a/memoryleak.htm

Para quem não teve estes problemas ainda possui um software plenamente funcional, rápido e com um pouco mais de trabalho pode se desenvolver qualquer coisa que é feita hoje em dia, pois a Microsoft garante a compatibilidade da API Win32 (conceito que significa código nativo e não só para 32 bits). Assim como o modelo de  programas em Delphi escritos em código nativo, nos dias hoje a Microsoft disponibiliza este tipo de  ferramenta apenas para C++, e este tipo de programação não pode ser desenvolvida à partir de uma versão Express do Visual Studio, pois a aplicação nativa é ideal para softwares coorporativos por ser consideravelmente mais rápida do que aplicações utilizando o framework.

Código Nativo – Win32 : http://msdn.microsoft.com/pt-br/library/hh875053.aspx

Delphi possui a melhor IDE RAD de todos os tempos, suporta vários tipos de conexões incluindo os melhores bancos de dados do mundo, é multi-plataforma, possui código nativo com acesso pleno a API de plataforma, incluindo plataformas mobiles.

Embarcadero: https://www.embarcadero.com/br

Delphi Language: http://docwiki.embarcadero.com/RADStudio/XE3/en/Language_Overview

Rad Studio XE7

RAD Studio XE7

Migração Delphi – Java ou C#

Muitos proprietários e gerentes de TI se deixam levar por toda propaganda em torno das linguagens Java e C#, o que você deve lembrar é que você esta lidando com a Oracle e a Microsoft e um orçamento enorme para marketing mundial, isto significa que os softwares principais ou seja, produtos de primeira linha para o segmento empresarial que fazem praticamente tudo e estão no topo da tecnologia, os “ERPs” das grandes empresas fornecidos pela Oracle e Microsoft que provavelmente são concorrentes direto, senão em um todo em algum módulo do produto que você planeja desenvolver e possivelmente são vendidos por um valor muito maior do que seu produto final será, estes produtos topo de linha não foram desenvolvidos e nem utilizam Java e .NET, o Oracle JDEdwards utiliza Event Rule Language, C e C++ e o Microsoft Dynamics AX (C++) utiliza sua IDE MorphX e a linguagem X++ e foi desenvolvido originalmente pela IBM, então você não deve tornar nenhuma das marcas registradas seu time do coração antes de conhecer as mesmas razoavelmente. Não pense que você vai desenvolver o próximo JDE ou Dynamics usando Java ou C#, até porque os bancos de dados renomados fabricados pelas mesmas empresas detentoras dos ERPs possuem Features exclusivas para os mesmos e assim também acontece com o SAP R/3 que é líder no mercado empresarial e a Oracle e a Microsoft se orgulham em dizer que seus bancos de dados são certificados para as aplicações SAP.

É claro que você pode desenvolver ótimos e robustos softwares com as linguagens Java e C# mas tenha em mente que investir em infraestrutura, conhecimento técnico e funcional é muito importante, por isto se você é testemunha de problemas descritos no tópico acima simplesmente migrar para uma destas linguagens por si só não vai resolver seu problema, muito pelo contrario, Java é baseado em C++ e C# é baseado em Java, assim o conceito de objetos, classes, coleções, iteradores entre outros, demanda uma curva de aprendizado relativamente maior que o aprendizado exigido pela linguagem Object Pascal, sem contar que o programador também deve conhecer como funciona o sistema operacional em questão independente da linguagem ser ou não multi plataforma.

Dependendo do tipo de projeto, hoje, também vale a pena utilizar linguagens que vem ganhando muito espaço no mercado internacional e no Brasil, como Ruby e Python que possuem uma comunidade muito ativa. No exterior Python é ensinado a crianças nas escolas e muitos a veem como uma linguagem do futuro. Estas linguagens são multi plataforma, muito versáteis e puramente orientadas a objeto, apesar do Python não possuir oficialmente esta classificação é bem similar ao Ruby, na verdade Ruby que foi inspirado em Python, e de qualquer modo Python e Ruby possuem uma orientação a objeto mais pura que Java e C# pois não possuem tipos primitivos possibilitando cortar alguns caminhos na hora da codificação, além do beneficio de que as duas linguagens possuem uma sintaxe simples e minimalista, fazem a mesma coisa requerendo muito menos linhas de código e ainda por cima de um modo mais fácil.

Já o Java e o C# herdam a sintaxe e conceitos do C++, inclusive o C# trouxe do C++ muita coisa que o Java aboliu, como ponteiros e Structs, as duas linguagens na pratica são muito similares e ambas já são linguagens conceituadas. Uma vantagem é que Java, Ruby e Python são linguagens que possuem muitos frameworks de código aberto sob diversas licenças, evoluem mais rápido do que o C# que vai incorporar as novidades só em sua próxima versão ou na próxima versão do Windows que agregará novas tecnologias, muitas delas vindas ou inspiradas no código aberto, como vários frameworks Java que também foram escritos para C# mais tarde, e o próprio ASP.NET MVC que foi e ainda é altamente influenciado pelo framework Rails.

Entretanto a Microsoft já se mobilizou para tentar mudar esta situação criando uma serie de medidas, lançando uma versão comunitária do Visual Studio, adotando o Python e outras linguagens e as integrando ao Visual Studio, firmando parcerias com empresas como a Apache incorporando o Apache Córdoba e a empresa Xamarim que patrocina o Mono (Linux) e é proprietária da plataforma Xamarim (OS X e Android), outra medida também foi abrir o código fonte da tecnologia ASP.NET tornando seus frameworks abertos sob a licença Apache, para que possam sofrer mais influencias da comunidade de código aberto, pretende também em um futuro próximo, abrir o código do núcleo do .Net Framework para que se torne autossuficiente em outras plataformas. Influencia esta que o Java e outras linguagens já possuem e atuam fortemente em todas as plataformas (Unix, Linux, Windows, OS X e diversos devices), inclusive na tecnologia Cloud, onde a Oracle proprietária do Java há tempos já lançou o primeiro sistema operacional exclusivo para as nuvens, o Oracle Solaris 11, em contrapartida as varias distribuições Linux Enterprise como a RedHat também estão investindo fortemente na plataforma Cloud, como por exemplo a plataforma hibrida OpenShift que suporta serviços em varias linguagens e bancos de dados diferentes, enquanto a Microsoft foca exclusivamente na sua tecnologia Azure, MSSQL Server, na interoperabilidade com o sistema operacional Linux Suse Enterprise e em suas novas parcerias.

Durante todas estas reviravoltas tecnológicas no universo do código aberto e no mundo proprietário, batalhas judiciais pelas patentes de softwares e devices, o Delphi apenas corre atrás das velhas novidades, ainda tentando mover usuários (sem perde-los) de sua plataforma Win32 para as suas novas plataformas proprietárias (livre somente de royalts) que competem com vários outros frameworks mais atuais, muitos deles de código aberto e ou gratuitos.

Conectividade Delphi: http://www.embarcadero.com/br/products/delphi/connect

Uma das mais famosas bibliotecas C++ no qual Java e C# foram baseados:

Standard Template Library: http://msdn.microsoft.com/en-us/library/c191tb28.aspx

STL/CLR Library: http://msdn.microsoft.com/en-us/library/bb385954.aspx

JCF – Framework: http://docs.oracle.com/javase/tutorial/collections/intro

No Brasil a linguagem de programação C# é a queridinha das empresas de pequeno e médio porte, isto é devido as diversas ações que a Microsoft executa no mercado nacional com seus programas, entre eles as certificações com escolas credenciadas, Microsoft Partners e inúmeras convenções e encontros, já o Java atua soberano no mercado de software para Main Frames e Devices, desenvolve-se em Java também dentro de softwares de grande porte, incluindo softwares da Oracle, IBM, Google e SAP, como no banco de dados Oracle e IBM DB2, que rodam rotinas em Java, além destas quatro companhias também possuírem uma IDE exclusiva para programar em Java, elas são NetBeans (Oracle), Eclipse (IBM), Android Studio (Google) e NetWeaver para Java da SAP, em sua nova tecnologia para as nuvens SAP HANA a SAP adota a IDE Eclipse como sua nova plataforma de desenvolvimento. Sem contar outras inúmeras tecnologias profissionais e servidores de aplicações Enterprise para Java como Oracle WebLogic, IBM WebSphere, TomCat da Apache, JBoss da Red Hat.

Fora do Brasil o C# esta qualificado com apenas 7.4% no ranking de linguagens mais procuradas pelas empresas, enquanto Java possui 19,6%, segundo o site CodeEval o ranking das linguagens mais populares de 2015 são: Ranking Code Eval.

Já no Tiobe Index 2015, a linguagem Java aparece em segundo lugar, C# ocupa a quarta posição enquanto Delphi desde 2013 se localiza abaixo da decima sétima posição, você pode conferir o ranking mensal da Tiobe aqui: Tiobe Index 2015. Nos dois índices Java e C# ocupam posições similares no ranking.

Uma ótima ilustração para os parágrafos acima pode ser utilizando a ótica da empresa SAP (Lider mundial de software corporativo). Seu principal produto o SAP R/3 para grandes empresas utiliza opcionalmente Java como linguagem de desenvolvimento e também no núcleo algumas de suas aplicações, já seu produto para pequenas empresas chamado Business One utiliza .NET. Independe dos motivos quem conhece as duas aplicações sabe da diferença enorme da tecnologia entre elas.

Para uma comparação técnica completa entre Java e C#, utilize o link a seguir:

C# for Java Developers: http://msdn.microsoft.com/en-us/library/ms228358(v=vs.90).aspx

Legados do Delphi

Java

Se tratando do Java seu conceito de objetos e sintaxe são baseados em C++ e em bibliotecas como a STL (Standard Template Library), mas o Delphi deixou um importante legado que é a IDE visual do NetBeans, originalmente denominada Xelfi e desenvolvida na República Tcheca em 1996. O objetivo era escrever uma IDE Java similar ao Delphi. O Xelfi foi a primeira IDE escrita em Java e posteriormente comprada pela SUN, que hoje pertence a Oracle e os exemplos oficiais são escritos para está IDE, inclusive a plataforma Java SEEE podem ser baixadas em pacotes (Bundle) que já contemplam o NetBeans, o servidor de aplicação GlassFish e os plugins para sua interface RAD (Desktop com Java Swing, Java FX e Web).

NetBeans History: https://netbeans.org/about/history.html

C#

Microsoft já namorava o arquiteto por trás do Delphi e de seu predecessor Turbo Pascal foi Anders Hejlsberg, onde se tornou o arquiteto responsável pelo projeto do C# e foi peça chave na criação do ambiente Microsoft .NET. Então é de se supor que o C# leva um pouco do Delphi dentro de si e podemos ver isto claramente na sintaxe de algumas instruções, principalmente no que se refere ao conceito de Eventos (Sender) e Setter (Getter e Setter).

C# Language: http://msdn.microsoft.com/pt-br/library/z1zx9t92.aspx

Métodos Getter e Setter

Em Java, C++ e C# existe o conceito de Getter e Setter  (inclusive sintaxe idênticas) para métodos de classe que em Delphi seria “equivalente” a uma Function e uma Procedure. Java e C++ seguem o padrão comum para o método Setter, em C# a Microsoft ensina o conceito como do Java quando você cria uma classe, o Visual Studio possui um atalho para criar Getter e Setter automaticamente mas não utilizando métodos, assim como os objetos do framework usam a sintaxe do Delphi, embutindo o conceito de Getter e Setter dentro de uma propriedade ou seja um método Getter para Java e C++, exemplo:

Getter e Setter  – Java: http://docs.oracle.com/javaee/6/tutorial/doc/gjbbp.html

Getter e Setter – C#: http://msdn.microsoft.com/en-us/library/w86s7x04.aspx

Então em C# é possível utilizar o conceito comum de Getter e Setter baseado em C++ e Java, utilizar o conceito de Get e Set embutido dentro de um método Getter (propriedades em C#) é meramente opcional e apenas uma questão de sintaxe do objeto, no qual desenvolvedores Delphi estão bem familiarizados. Inclusive o conceito propriedades nos objetos C#, torna a IDE do Visual Studio, na questão pratica do ponto de vista do desenvolvedor muito similar a IDE do Delphi.

Delphi Properties: http://docwiki.embarcadero.com/RADStudio/XE3/en/Properties

Código Fonte Java e C#


// Java

Objeto.setVisible(True); // Setter

// C# e Delphi (Propriedades)

Objeto.Visible = True; // Setter porem igual ao Delphi*

// * O conceito de operadores Java e C# são iguais
//   Delphi usa := para atribuir um valor

Eventos – Windows (Win32) – Java – C#

Outra similaridade do C# com o Delphi são os eventos, o conceito de eventos do Windows a grosso modo é uma fila de mensagens que pode ser utilizado pela API através da função WindowProc ou WndProc e é mais similar ao Java que utiliza tipos de mensagens implementadas na classe (ActionListener, ItemListener, MouseListner e outros) por exemplo, o Java possui um ActionListner que identifica o evento de  clique de qualquer botão independente da quantidade de botões em um formulário utilizando apenas um método, já o C# assim como Delphi e a IDE RAD do NETBEANS para JAVA tornam está funcionalidade mais fácil porem geram um código maior criando um evento de clique para cada botão da tela.

WindowProc: http://msdn.microsoft.com/pt-br/library/ms633573.aspx

Windows Messages: http://msdn.microsoft.com/pt-br/library/ms644927.aspx

Java Event Listner: http://docs.oracle.com/javase/tutorial/uiswing/events/intro.html

C# Event Handler: http://msdn.microsoft.com/en-us/library/system.eventhandler(v=vs.110).aspx

Assim, você pode testemunhar a “semelhança” do conceito de Object Sender entre Delphi e o .Net Framework (VB.NET e C#), utilize os links abaixo para entender a sintaxe final do evento de clique de um botão.

Object Sender Delphi: http://docwiki.embarcadero.com/RADStudio/XE4/en/Using_the_Sender_Parameter

Object Sender .NET Framework: http://msdn.microsoft.com/en-us/library/aa457091.aspx

Soluções e Projetos

Um ponto muito importante no desenvolvimento para o C# (Java já utilizava o Apache Ant e soluções recentes utilizam o Apache Maven) é que a Microsoft sabia da dificuldade de muitos programadores em utilizar o conceito Win32 na arquitetura do software e estruturação do código fonte, então o que em Delphi exigia abrir um projeto tipo Dll (não gerenciado) escrever uma biblioteca adequada, importar as funções para seu projeto principal e assim por diante. No Visual Studio surgiu o conceito de solução, que unido a um ambiente gerenciado torna possível criar vários projetos por solução,  onde o projeto principal contendo um Windows Form,  por exemplo gera um executável e os projetos desta solução contendo apenas biblioteca de classes geram automaticamente uma Dll (ambiente gerenciado) que é referenciada ao projeto principal e esta resolvido o problema que possuíamos no Delphi de alguns desenvolvedores criando executáveis enormes e códigos redundantes.

Solution and Project Basics: http://msdn.microsoft.com/en-us/library/b142f8e7.aspx

Concluindo

Vale a pena migrar para uma linguagem mais moderna sempre, inovação faz parte da área de software, todos nós só temos a ganhar, melhores ferramentas, técnicas mais modernas, maior produtividade, o importante é avaliar caso a caso e criar um projeto consistente e na medida para que este processo se realize da melhor maneira possível.

O que vimos neste post é apenas uma primeira visão da importância do Delphi e como o Delphi influenciou outras linguagens de programação. Para uma comparação mais precisa é necessário um projeto bem elaborado e fica a mensagem de que o Delphi  pode ter desaparecido da grande mídia mas continuará vivo por muito tempo.

Em C++ MFC não existe um componente pronto para fazer o trabalho de redimensionamento de painéis, mas existe uma classe que encapsula a API do Windows que faz exatamente este trabalho e esta classe é  chamada de CSplitterWnd, a classe fornece a funcionalidade de uma janela de divisão, que é uma janela que contém vários painéis. Um objeto CSplitterWnd geralmente é incorporado em um CFrameWnd pai ou um objeto filho CMDIChildWnd, isto significa que esta classe utiliza um tipo de aplicação MDI e não uma aplicação baseada em diálogos.

É possível criar um workaround que utiliza um componente estático Picture Control para criar um Splitter que redimensiona os componentes e não painéis como faz a classe CSplitterWnd. Existe vários componentes prontos na internet para fazer isto, mas nós vamos utilizar uma classe de código aberto para fazer este trabalho.

Splitter Control

Splitter Control

 

Visual Studio

Vamos utilizar a classe CSplitterControl que é Open Source que você encontra logo abaixo:

  1. Crie um projeto MFC Dialog Based.
  2. Coloque na tela dois componentes Picture Control e nomeie um como IDC_IMAGEM e outro como IDC_SPLITTER1.
  3. Coloque um componente Edit Control e crie uma variável chamada m_texto;
  4. No componente IDC_IMAGEM mude sua propriedade Type para Bitmap.
  5. No componente IDC_SPLITTER1 mude sua propriedade Visible para False.
  6. No componente Edit Control mude sua propriedade MultiLines para True.
  7. Disponha os componentes como na imagem abaixo:

    Splitter Control - Design

    Splitter Control – Design

  8. Adicione a classe CSplitterControl em seu projeto.
  9. Efetue o Download da imagem e a transforme em BMP, você pode usar o Paint Brush do Windows: https://desenvolvimentoaberto.org/wp-content/uploads/2014/04/balonismo.jpg
  10. Copie os trechos marcados do código abaixo para seu código gerado automaticamente.

 

Exemplo:

Neste exemplo utilizamos uma classe Open Source Splitter Control para criar um Splitter à partir de um componente Picture Control que controla o tamanho dos componentes entre eles controlando seu tamanho baseado no valor do Splitter.

Obs: Lembre-se que os exemplos abaixo utilizam classes e as classes em C++ são divididas em dois arquivos.

C++

Porgrama – Classe meusplittercpp.h

// código gerado automaticamente
// meusplittercppDlg.h : header file
//

#pragma once
#include "afxwin.h"
#include "SplitterControl.h"

class CmeusplittercppDlg : public CDialogEx
{

public:
	CmeusplittercppDlg(CWnd* pParent = NULL);	

	enum { IDD = IDD_MEUSPLITTERCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	

	// Desenvolvimento Aberto
	virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);

protected:
	HICON m_hIcon;

	// Desenvolvimento Aberto
	void Redimensiona(int delta);
	void Append(CString texto);
	CSplitterControl m_wndSplitter1;
	// ******

	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	CEdit m_texto;
};

Porgrama – Classe meusplittercpp.cpp


// meusplittercppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "meusplittercpp.h"
#include "meusplittercppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CmeusplittercppDlg dialog

CmeusplittercppDlg::CmeusplittercppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CmeusplittercppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CmeusplittercppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT1, m_texto);
}

BEGIN_MESSAGE_MAP(CmeusplittercppDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
//	ON_WM_CREATE()
END_MESSAGE_MAP()

// CmeusplittercppDlg message handlers

BOOL CmeusplittercppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);		

	// Desenvolvimento Aberto
	// Inicializa componentes

	// Adiciona texto
	Append(L"O balonismo é um esporte aeronáutico praticado com um balão de ar quente.\n");
	Append(L"Possui adeptos em todo o mundo. No Brasil, o esporte começou a se popularizar\n");
	Append(L"a partir dos anos 90.\n");
	Append(L"O balão é considerado uma aeronave assim como avião, helicópteros e outros.\n");
	Append(L"Por esta razão o balão deve ter uma matricula (prefixo) registrado junto\n");
	Append(L"à ANAC, seu piloto deve possuir uma licença (brevê) específico para a pratica\n");
	Append(L"do balonismo também emitido pela ANAC.");

	// Cria componente Splitter Control baseado no componente Picture Control
	CRect rc;
	CWnd* pWnd;

	pWnd = GetDlgItem(IDC_SPLITTER1);
	pWnd->GetWindowRect(rc);
	ScreenToClient(rc);
	m_wndSplitter1.Create(WS_CHILD | WS_VISIBLE, rc, this, IDC_SPLITTER1);
	m_wndSplitter1.SetRange(50, 50, -1);

	// Carrega imagem

	CStatic * foto;
	CString imagem;

	foto = (CStatic *)GetDlgItem(IDC_IMAGEM);

	imagem = L"C:/Desenvolvimento Aberto/balonismo.bmp";

	HBITMAP pic = (HBITMAP)LoadImage(NULL, imagem, IMAGE_BITMAP,370, 260, LR_LOADFROMFILE);
	foto->SetBitmap(pic);

	// ***

	return TRUE;
}

void CmeusplittercppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CmeusplittercppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// Desenvolvimento Aberto
// Nosso código começa aqui

LRESULT CmeusplittercppDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	if (message == WM_NOTIFY)
	{
		if (wParam == IDC_SPLITTER1)
		{
			SPC_NMHDR* pHdr = (SPC_NMHDR*)lParam;
			Redimensiona(pHdr->delta);
		}
	}

	return CDialog::DefWindowProc(message, wParam, lParam);
}

void CmeusplittercppDlg::Redimensiona(int delta)
{
	CSplitterControl::ChangeWidth(GetDlgItem(IDC_IMAGEM), delta);
	CSplitterControl::ChangeWidth(&m_texto, -delta, CW_RIGHTALIGN);

	Invalidate();
	UpdateWindow();
}

void CmeusplittercppDlg::Append(CString texto)
{
	int tam1 = m_texto.GetWindowTextLengthW();
	m_texto.SetSel(tam1, tam1);
	m_texto.ReplaceSel(texto);

}

Splitter Control – Componente Open Source

Porgrama – Classe CSplitterControl.h

/**************CSplitterControl interface***********
*	Class name :CSplitterControl
*	Purpose: Implement splitter control for dialog
*			or any other windows.
*	Author: Nguyen Huy Hung, Vietnamese student.
*	Date:	May 29th 2002.
*	Note: You can use it for any purposes. Feel free
*			to change, modify, but please do not
*			remove this.
*	No warranty of any risks.
*	(:-)
*/
#if !defined(AFX_SPLITTERCONTROL_H__FEBBA242_B2C9_4403_B68D_E519D645CB15__INCLUDED_)
#define AFX_SPLITTERCONTROL_H__FEBBA242_B2C9_4403_B68D_E519D645CB15__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// SplitterControl.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CSplitterControl window
#define SPN_SIZED WM_USER + 1
#define CW_LEFTALIGN 1
#define CW_RIGHTALIGN 2
#define CW_TOPALIGN 3
#define CW_BOTTOMALIGN 4
#define SPS_VERTICAL 1
#define SPS_HORIZONTAL 2
typedef struct SPC_NMHDR
{
	NMHDR hdr;
	int delta;
} SPC_NMHDR;

class CSplitterControl : public CStatic
{
// Construction
public:
	CSplitterControl();

// Attributes
public:
protected:
	BOOL		m_bIsPressed;
	int			m_nType;
	int			m_nX, m_nY;
	int			m_nMin, m_nMax;
	int			m_nSavePos;		// Save point on the lbutton down
								// message
// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CSplitterControl)
	//}}AFX_VIRTUAL

// Implementation
public:
	static void ChangePos(CWnd* pWnd, int dx, int dy);
	static void ChangeWidth(CWnd* pWnd, int dx, DWORD dwFlag = CW_LEFTALIGN);
	static void ChangeHeight(CWnd* pWnd, int dy, DWORD dwFlag = CW_TOPALIGN);
public:
	void		SetRange(int nMin, int nMax);
	void		SetRange(int nSubtraction, int nAddition, int nRoot);

	int			GetStyle();
	int			SetStyle(int nStyle = SPS_VERTICAL);
	void		Create(DWORD dwStyle, const CRect& rect, CWnd* pParent, UINT nID);
	virtual		~CSplitterControl();

	// Generated message map functions
protected:
	virtual void	DrawLine(CDC* pDC, int x, int y);
	void			MoveWindowTo(CPoint pt);
	//{{AFX_MSG(CSplitterControl)
	afx_msg void	OnPaint();
	afx_msg void	OnMouseMove(UINT nFlags, CPoint point);
	afx_msg BOOL	OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg void	OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void	OnLButtonUp(UINT nFlags, CPoint point);
	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_SPLITTERCONTROL_H__FEBBA242_B2C9_4403_B68D_E519D645CB15__INCLUDED_)

Porgrama – Classe CSplitterControl.cpp

// SplitterControl.cpp : implementation file
//

#include "stdafx.h"
#include "SplitterControl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSplitterControl

// hCursor1 is for vertiacal one
// and hCursor2 is for horizontal one
static HCURSOR SplitterControl_hCursor1 = NULL;
static HCURSOR SplitterControl_hCursor2 = NULL;

CSplitterControl::CSplitterControl()
{
	// Mouse is pressed down or not ?
	m_bIsPressed = FALSE;	

	// Min and Max range of the splitter.
	m_nMin = m_nMax = -1;
}

CSplitterControl::~CSplitterControl()
{
}

BEGIN_MESSAGE_MAP(CSplitterControl, CStatic)
	//{{AFX_MSG_MAP(CSplitterControl)
	ON_WM_PAINT()
	ON_WM_MOUSEMOVE()
	ON_WM_SETCURSOR()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSplitterControl message handlers

/****************************************************
*	Create(DWORD dwStyle, const CRect& rect, CWnd* pParent, nID)
*	Use this function instead of the CStatic::Create function
* Parameters: No need to explain (see MSDN (:-) )
*
****************************************************/
void CSplitterControl::Create(DWORD dwStyle, const CRect &rect, CWnd *pParent, UINT nID)
{
	CRect rc = rect;
	dwStyle |= SS_NOTIFY;

	// Determine default type base on it's size.
	m_nType = (rc.Width() < rc.Height())?
					SPS_VERTICAL:
					SPS_HORIZONTAL;

	if (m_nType == SPS_VERTICAL)
		rc.right = rc.left + 5;
	else // SPS_HORIZONTAL
		rc.bottom = rc.top + 5;

	CStatic::Create(L"", dwStyle, rc, pParent, nID);

	if (!SplitterControl_hCursor1)
	{
		SplitterControl_hCursor1 = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE);
		SplitterControl_hCursor2 = AfxGetApp()->LoadStandardCursor(IDC_SIZENS);
	}

	// force the splitter not to be splited.
	SetRange(0, 0, -1);
}

// Set style for splitter control
// nStyle = SPS_VERTICAL or SPS_HORIZONTAL
int CSplitterControl::SetStyle(int nStyle)
{
	int m_nOldStyle = m_nType;
	m_nType = nStyle;
	return m_nOldStyle;
}
int CSplitterControl::GetStyle()
{
	return m_nType;
}

void CSplitterControl::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	CRect rcClient;
	GetClientRect(rcClient);

	CBrush br, *pOB;
	CPen pen, *pOP;

	dc.Draw3dRect(rcClient, GetSysColor(COLOR_BTNHIGHLIGHT), GetSysColor(COLOR_BTNSHADOW));
	rcClient.DeflateRect(1,1,1,1);

	pen.CreatePen(0, 1, RGB(200, 200, 200));
	br.CreateSolidBrush(RGB(200, 220, 220));
	pOB = dc.SelectObject(&br);
	pOP = dc.SelectObject(&pen);

	dc.Rectangle(rcClient);

	// Restore pen and brush
	DeleteObject(dc.SelectObject(pOB));
	DeleteObject(dc.SelectObject(pOP));
}

void CSplitterControl::OnMouseMove(UINT nFlags, CPoint point)
{
	if (m_bIsPressed)
	{
		CWindowDC dc(NULL);
		DrawLine(&dc, m_nX, m_nY);

		CPoint pt = point;
		ClientToScreen(&pt);
		GetParent()->ScreenToClient(&pt);

		if (pt.x < m_nMin)
			pt.x = m_nMin;
		if (pt.y < m_nMin)
			pt.y = m_nMin;

		if (pt.x > m_nMax)
			pt.x = m_nMax;
		if (pt.y > m_nMax)
			pt.y = m_nMax;

		GetParent()->ClientToScreen(&pt);
		m_nX = pt.x;
		m_nY = pt.y;
		DrawLine(&dc, m_nX, m_nY);
	}
	CStatic::OnMouseMove(nFlags, point);
}

BOOL CSplitterControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	if (nHitTest == HTCLIENT)
	{
		(m_nType == SPS_VERTICAL)?(::SetCursor(SplitterControl_hCursor1))
			:(::SetCursor(SplitterControl_hCursor2));
		return 0;
	}
	else
		return CStatic::OnSetCursor(pWnd, nHitTest, message);
}

void CSplitterControl::OnLButtonDown(UINT nFlags, CPoint point)
{
	CStatic::OnLButtonDown(nFlags, point);

	m_bIsPressed = TRUE;
	SetCapture();
	CRect rcWnd;
	GetWindowRect(rcWnd);

	if (m_nType == SPS_VERTICAL)
		m_nX = rcWnd.left + rcWnd.Width() / 2;	

	else
		m_nY = rcWnd.top  + rcWnd.Height() / 2;

	if (m_nType == SPS_VERTICAL)
		m_nSavePos = m_nX;
	else
		m_nSavePos = m_nY;

	CWindowDC dc(NULL);
	DrawLine(&dc, m_nX, m_nY);
}

void CSplitterControl::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (m_bIsPressed)
	{
		ClientToScreen(&point);
		CWindowDC dc(NULL);

		DrawLine(&dc, m_nX, m_nY);
		CPoint pt(m_nX, m_nY);
		m_bIsPressed = FALSE;
		CWnd *pOwner = GetOwner();
		if (pOwner && IsWindow(pOwner->m_hWnd))
		{
			CRect rc;
			int delta;
			pOwner->GetClientRect(rc);
			pOwner->ScreenToClient(&pt);
			MoveWindowTo(pt);

			if (m_nType == SPS_VERTICAL)
				delta = m_nX - m_nSavePos;
			else
				delta = m_nY - m_nSavePos;

			SPC_NMHDR nmsp;

			nmsp.hdr.hwndFrom = m_hWnd;
			nmsp.hdr.idFrom   = GetDlgCtrlID();
			nmsp.hdr.code     = SPN_SIZED;
			nmsp.delta = delta;

			pOwner->SendMessage(WM_NOTIFY, nmsp.hdr.idFrom, (LPARAM)&nmsp);
		}
	}

	CStatic::OnLButtonUp(nFlags, point);
	ReleaseCapture();
}

void CSplitterControl::DrawLine(CDC* pDC, int x, int y)
{
	int nRop = pDC->SetROP2(R2_NOTXORPEN);

	CRect rcWnd;
	int d = 1;
	GetWindowRect(rcWnd);
	CPen  pen;
	pen.CreatePen(0, 1, RGB(200, 200, 200));
	CPen *pOP = pDC->SelectObject(&pen);

	if (m_nType == SPS_VERTICAL)
	{
		pDC->MoveTo(m_nX - d, rcWnd.top);
		pDC->LineTo(m_nX - d, rcWnd.bottom);

		pDC->MoveTo(m_nX + d, rcWnd.top);
		pDC->LineTo(m_nX + d, rcWnd.bottom);
	}
	else // m_nType == SPS_HORIZONTAL
	{
		pDC->MoveTo(rcWnd.left, m_nY - d);
		pDC->LineTo(rcWnd.right, m_nY - d);

		pDC->MoveTo(rcWnd.left, m_nY + d);
		pDC->LineTo(rcWnd.right, m_nY + d);
	}
	pDC->SetROP2(nRop);
	pDC->SelectObject(pOP);
}

void CSplitterControl::MoveWindowTo(CPoint pt)
{
	CRect rc;
	GetWindowRect(rc);
	CWnd* pParent;
	pParent = GetParent();
	if (!pParent || !::IsWindow(pParent->m_hWnd))
		return;

	pParent->ScreenToClient(rc);
	if (m_nType == SPS_VERTICAL)
	{
		int nMidX = (rc.left + rc.right) / 2;
		int dx = pt.x - nMidX;
		rc.OffsetRect(dx, 0);
	}
	else
	{
		int nMidY = (rc.top + rc.bottom) / 2;
		int dy = pt.y - nMidY;
		rc.OffsetRect(0, dy);
	}
	MoveWindow(rc);
}

void CSplitterControl::ChangeWidth(CWnd *pWnd, int dx, DWORD dwFlag)
{
	CWnd* pParent = pWnd->GetParent();
	if (pParent && ::IsWindow(pParent->m_hWnd))
	{
		CRect rcWnd;
		pWnd->GetWindowRect(rcWnd);
		pParent->ScreenToClient(rcWnd);
		if (dwFlag == CW_LEFTALIGN)
			rcWnd.right += dx;
		else if (dwFlag == CW_RIGHTALIGN)
			rcWnd.left -= dx;
		pWnd->MoveWindow(rcWnd);
	}
}

void CSplitterControl::ChangeHeight(CWnd *pWnd, int dy, DWORD dwFlag)
{
	CWnd* pParent = pWnd->GetParent();
	if (pParent && ::IsWindow(pParent->m_hWnd))
	{
		CRect rcWnd;
		pWnd->GetWindowRect(rcWnd);
		pParent->ScreenToClient(rcWnd);
		if (dwFlag == CW_TOPALIGN)
			rcWnd.bottom += dy;
		else if (dwFlag == CW_BOTTOMALIGN)
			rcWnd.top -= dy;
		pWnd->MoveWindow(rcWnd);
	}
}

void CSplitterControl::ChangePos(CWnd* pWnd, int dx, int dy)
{
	CWnd* pParent = pWnd->GetParent();
	if (pParent && ::IsWindow(pParent->m_hWnd))
	{
		CRect rcWnd;
		pWnd->GetWindowRect(rcWnd);
		pParent->ScreenToClient(rcWnd);
		rcWnd.OffsetRect(-dx, dy);

		pWnd->MoveWindow(rcWnd);
	}
}

void CSplitterControl::SetRange(int nMin, int nMax)
{
	m_nMin = nMin;
	m_nMax = nMax;
}

// Set splitter range from (nRoot - nSubtraction) to (nRoot + nAddition)
// If (nRoot < 0)
//		nRoot =  <current position of the splitter>
void CSplitterControl::SetRange(int nSubtraction, int nAddition, int nRoot)
{
	if (nRoot < 0)
	{
		CRect rcWnd;
		GetWindowRect(rcWnd);
		if (m_nType == SPS_VERTICAL)
			nRoot = rcWnd.left + rcWnd.Width() / 2;
		else // if m_nType == SPS_HORIZONTAL
			nRoot = rcWnd.top + rcWnd.Height() / 2;
	}
	m_nMin = nRoot - nSubtraction;
	m_nMax = nRoot + nAddition;
}