Jx Random Quote

There was a boy called Eustace Clarence Scrubb, and he almost deserved it. -- C. S. Lewis, The Chronicles of Narnia
Главная arrow Статьи arrow Создание программы - MySQL DatabaseBrowser. Часть 1
Создание программы - MySQL DatabaseBrowser. Часть 1 Версия в формате PDF Версия для печати Отправить на e-mail
 
 
         Сейчас использование баз данных, в то числе и удаленных стало обычной и повседневной практикой. Очень часто используется и СУБД MySQL – свободной распространяемая система управления базами данных. В основном она используется для малых и средних предприятий, где успешно решает многие задачи. Ее бесплатность, доступность, стабильность в работе и прочие характеристики позволяет говорить об это СУБД как о массовой альтернативе таких баз как InterBase или SyBase. Последние версии этой программы, существенно расширяющие ее возможности предлагают решение многих проблем, с которым сталкиваются как администратор баз данных, так и обычный пользователь.
Однако, существуют так же и проблемы при работе с Windows, как обязательное наличие драйверов ODBC   для MySQL, если СУБД работает в этой среде. Стандартный клиент для MySQL не является удобным в настоящее время, так как является консольной программой. Опять же, требуется как минимум наличие установленной копии программы MySQL сервер на компьютере пользователя. Просмотр данных и простое редактирование также в стандартном клиенте не отвечает современным требованиям к интерфейсу. Решение целого ряда повседневных задач, предполагает стандартизацию  пользовательского интерфейса и  создание удобного юзабилити.
 Поэтому мы пришли к необходимости создания собственного клиентского приложения  Целью данного проекта является создание программы, которая бы позволяла выполнять наиболее общие операции с СУБД MySQL в операционной системе Windows, и при это не требовала наличия и настройки ODBC драйвера. Обычно это не умеет делать средний пользователь, и следовательно здесь требуется помощь администратора, что создает дополнительные трудности и самое главное, потерю рабочего времени.  Кроме того, эта программа должна уметь соединяться и работать с удаленным MySQL сервером.  Сам проект на данном этапе не является окончательной версией программы, поэтому реализуется с наиболее общими возможностями.
Далее будет описано шаг за шагом процесс создания проекта и с примерами исходного кода.


В  начале мы создаем шаблон проекта. Для этого мы в Visual Studio выбираем  «MFC APPWizard» и вводим название проекта «Myslqlone» . Далее, «Шаге1» выбираем «Single Document». В «Шаге2» и в «Шаге3»  не меняем ничего,
в «Шаге 4» отключаем «Printing and Print Preview» и переключаем радиобокс на «Internet Explorer Rebars”. В «Шаге 5» выбираем из 2 радиобоксов «Windows Explorer». На конец, в «Шаге 6»  нажимаем  кнопку «Finish».  Выбранный нами тип проекта приложения наиболее полно отвечает решению поставленной задачи. В нем находятся изначально 2 удобных класса, «CleftView”, который
является потомком класса «CtreeCtrl» в нашем случае, «CmysqloneView», который в свою очередь наследует от «ClistView», что очень удобно и ускоряет процесс разработки проекта.  Оба эти класса могут использовать возможности
контролов ClistCtrl  и  CtreeCTrl,  от которых они порождены. Данные обстоятельства в последствии будут нами постоянно использоваться в этом проекте..
Все дальнейшие действия разбиты на этапы и описываются здесь ниже.  


1. Копируем   2 файла в папку проекта: «libmysql.dll»  и «libmysql.lib» из папки MySQL Server 4.1/lib/.  Затем подключаем к проекту файл «libmysql.lib». Нам потребуется этий файлы для обеспечения работы программы и доступа к MySQL API функциям. Мы будем использовать MySQL C API функции,
как наиболее стабильно работающие и обеспечивающие полный сервис.

2. Затем  копируем все заголовочные файлы  из директории MySQL Server 4.1/include/ все заголовочные файлы в директориюVC /include/ Visual Studio.
Это также необходимо для создания и компиляции проекта.

3. Подключаем в файл “mysql.h” к  файлу «stdafx.h» :
     #include "mysql.h"

4. Создаем переменную класса CImageList m_TreeImages в классе
 «CleftView.cpp» Она будет использована для создания  списка изображени\й, которые будут в свою очередь использованы в создаваемом объекте типа CtreeCtrl.

5. Создаем в файле  ресурсов новый ресурс.


6. Создаем в классе «CleftView.cpp» новый метод void FellTree():
void CLeftView::FillTree()
{
    CTreeCtrl & m_tree = GetTreeCtrl();
    m_tree.DeleteAllItems();
      
    m_tree.SetImageList(&m_TreeImages, TVSIL_NORMAL);


    HTREEITEM hRoot;

    CMysqloneDoc* pDoc = GetDocument();

    for (int i = 0; i < pDoc->m_available_bases.GetSize(); i++)
    {
        hRoot = m_tree.InsertItem(pDoc->m_available_bases[i], 0, 1);
    }


}

7. Создаем в методе класса  «CleftView.cpp» :OnInitialUpdate()
объект класса CimageList:

    m_TreeImages.Create(IDB_BITMAP1, 16, 1, RGB(255, 255, 255));
Это создает список пиктограмм для CtreeCtrl

8. Добавляем в этот же класс метод OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) для обработки события смены  элементов списка.

9. Вставляем в этот метод такой код:

void CLeftView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

    CTreeCtrl & m_tree = GetTreeCtrl();
    CMysqloneDoc* pDoc = GetDocument();
    if (!pDoc->connected) {return;}
    pDoc->current_table = "";
    HTREEITEM nodSelected = m_tree.GetSelectedItem();

    if (nodSelected>=0) {

    CString strSelected=m_tree.GetItemText(nodSelected);
    GetDocument()->SetTitle(strSelected);
    }


    HTREEITEM parent;
    parent = m_tree.GetParentItem (nodSelected);
    if (parent) {
        pDoc->current_table = m_tree.GetItemText (nodSelected);
        
        pDoc->UpdateAllViews (this);
        return;
    }



    HTREEITEM child;
    while (child = m_tree.GetChildItem (nodSelected)) {
        m_tree.DeleteItem (child);
    }



    CString base_name = m_tree.GetItemText (nodSelected);
    pDoc->current_base = base_name;

    MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
    MYSQL_RES * my_res;
    MYSQL_ROW row;
    CString sql;

    mysql_select_db (mysql, base_name.GetBuffer(125));
    if (mysql_query (mysql, "SHOW TABLES")) {
        AfxMessageBox ("Query SHOW databases failed");
        return;
    }
    my_res = mysql_store_result(mysql);
    while (row = mysql_fetch_row (my_res)) {
        char buffer[255];
        strcpy (buffer, row[0]);
        m_tree.InsertItem (_T(buffer), nodSelected);
    }
    mysql_free_result (my_res);

    
    *pResult = 0;
}


10. Добавляем новый ресурс – диалоговое окно. Туда вставляем 3 поля редактирования,одному из них в стилях проставляем стиль: «password» . Далее мы заходи в  Class Wizard и создаем новый класс для данного диалога. Назовем его «CLoginDlg». Он будет наследоваться от класса CDialog. Далее к  каждому из полей редактирования создаем переменные типа Cstring.  Это будут переменные этого класса для ввода данных по соединению с MySQL сервером.

11. Затем мы создаем переменную типа MYSQL mysql для класса «CmysqloneApp.cpp», это класс приложения. Эта переменная будет использоваться нами далее везде в программе для доступа к функциям MySQL.
Затем создаем в этом же классе новый метод для соединения с сервером баз    данных. типа BOOL ConnectToDb(). Вот его код:


BOOL CMysqloneApp::ConnectToDb()
{
   CLoginDlg dlg;

    while (dlg.DoModal()== IDOK) {
        if(!mysql_init(&mysql)){AfxMessageBox ("Can't make initialization to mysql server!");}
        if(mysql_real_connect(&mysql,dlg.m_host, dlg.m_login,dlg.m_password,NULL,0,NULL,0)){
            return TRUE;
        }
    }
    return FALSE;

}
В этом методе вызывается диалоговое окно CloginDlg, чтобы считать введенные пользователем данные и выполнить соединение с MySQL сервером.  Данные пользователя хранятся в специальном файле, с расширением «.lgn», который предоставляет администратор. Ниже приводится код метода подключения к серверу баз данных:
void CLoginDlg::OnBnClickedLogin()
{
    UpdateData();

    char login[35];
    char password[25];
    char host[255];
    FILE *file;
    bool valid_login = false;

    if( m_login =="")
    {
        AfxMessageBox("You must provide a username and password or click Cancel!");
        return;
    }
    if( m_password =="")
    {
        AfxMessageBox("Invalid login entered");
        return;
    }


    if( m_host =="")
    {
        AfxMessageBox("Enter host name, please");
        return;
    }

    try {
        
        file = fopen("database.lgn", "r");

    
        while( !feof(file) )
        {
            
            fscanf(file, "%s", login);

            
            if( strcmp((LPCTSTR)m_login, login) == 0 )
            {
                
                fscanf(file, "%s", password);
            
            
                if( strcmp((LPCTSTR)m_password, password) == 0 )
                {
                    valid_login = true;
                }
                else
                    valid_login = false;
            }
        }
        if( valid_login == true )
            OnOK();
        else
        {
            AfxMessageBox("Invalid entry data entered! Please try again");
            
        }

        fclose(file);
    }
    catch(...)
    {
        AfxMessageBox("Could not validate entered information to connect with MySQL database");
    }
    
    UpdateData(FALSE);

}
 

12. Подключаем заголовочный файл класса «CloginDlg.cpp» –  «LoginDlg.h» к
к файлу класса «CMysqloneApp»-«mysqlone.cpp»

#include "LoginDlg.h"

13. Создаем еще один метод для этого же класса типа void ExecuteSQL(CString sql). Он будет использоваться для выполнения запросов к MySQL серверу.
Вот его код:

void CMysqloneApp::ExecuteSQL(CString sql)
{

    mysql_query (&mysql, sql);

}

Он также будет использоваться повсеместно в работе программы.

14. Затем мы создаем новые переменные для класса «CmysqloneDoc.cpp»
    CStringArray m_available_bases; //текстовой массив списка доступных  .//баз.
    CString current_base; //переменная строкового типа для имени текущей //базы
    CString current_table; //строковая переменная для имени текущей таблицы
    bool connected;// переменная булевого типа для состояния соединения с //MySQL сервером.

15. На конец, вставляем следующий код вызова метода ConnectToDb() в
«CMysqloneApp»-«mysqlone.cpp» в метод InitInstance():

SetRegistryKey(_T("MySQLOne- MySQL Database Browser"));

LoadStdProfileSettings();  // Load standard INI file options (including MRU)

//После этих строк.

    if (!ConnectToDb()) {
        AfxMessageBox ("Could not connect to base\nQuitting");
        return FALSE;
    }

Метод ConnectToDb() будет вызываться при запуске программы, а поскольку он булевого типа, то про возращении этим методом FALSE программа не будет работать.
Теперь добавим еще  один метод, который будет выбирать базу данных для дальнейшего использования.


void CMysqloneApp::ChangeCurrentBase(CString newBaseName)
{
    mysql_select_db (&mysql, newBaseName);
}

16. Далее мы переходим в класс «CleftView.cpp» и через Class Wizard добавляем туда метод OnUpdate. Это один из поддерживаемых представлением методов, который нам нужно переопределить таким образом:  

void CLeftView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
    
    CTreeCtrl & m_tree = GetTreeCtrl();
    CMysqloneDoc* pDoc = GetDocument();
    if (!pDoc->connected) {
        m_tree.DeleteAllItems();
        return;
    }
    FeelTree();
    
}


17. Затем мы переходим снова к класс «CmysqloneDoc.cpp» и переопределяем метод OnNewDocument():

    
BOOL CMysqloneDoc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;

    current_table = "";

    MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
    MYSQL_RES * my_res;
    MYSQL_ROW row;
    if (mysql_query (mysql, "SHOW databases")) {
        AfxMessageBox ("Query SHOW databases failed");
        return TRUE;
    }
    my_res = mysql_store_result(mysql);
    int num = mysql_num_rows (my_res);
    
    m_available_bases.RemoveAll();
        while (row = mysql_fetch_row (my_res)) {
        m_available_bases.Add (row[0]);        
    }

    mysql_free_result (my_res);
    current_base = "";
    return TRUE;

}


18. Теперь переходим в класс «CmysqloneView.cpp», где добавляем в метод этого класса     OnInitialUpdate() следующий код для создания объекта типа ClistCTrl и задания его стилей отображения.

void CMysqloneView::OnInitialUpdate()
{
    CListView::OnInitialUpdate();
          CListCtrl &m_list = GetListCtrl();
    m_list.ModifyStyle(NULL, LVS_REPORT);
    m_list.SetExtendedStyle (LVS_EX_GRIDLINES );

    
}


19. Далее мы идем снова в Class Wizard и там добавляем в класс  «CmysqloneView.cpp» метод OnUpdate и помещаем туда такой код:

void CMysqloneView::OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/)
{
    CListCtrl &m_list = GetListCtrl();
    CMysqloneDoc*  pDoc = GetDocument();

    if (!pDoc->connected) {
        m_list.DeleteAllItems ();
        while(m_list.DeleteColumn(0));
        return;
    }
    if (pDoc->current_table == "") return;
    m_list.DeleteAllItems();
    while(m_list.DeleteColumn(0));

    MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
    MYSQL_RES * my_res;
    MYSQL_ROW row;
    CString sql;
    sql="SHOW COLUMNS IN ";
    sql += pDoc->current_table;
    mysql_query (mysql, sql);
    my_res = mysql_store_result (mysql);
    int i = 0;
    int counter = 0;
    while (row = mysql_fetch_row (my_res)) {
        m_list.InsertColumn (i, row[0], LVCFMT_LEFT, 100);
        i++;
    }
    counter = i;
    mysql_free_result (my_res);


    sql = "SELECT * FROM ";
    sql += pDoc->current_table;
    mysql_query (mysql, sql);
    my_res = mysql_store_result (mysql);
    i = 0;
    LVITEM item;
    item.mask = LVIF_TEXT;
    while (row = mysql_fetch_row (my_res)) {
        item.iItem = i;
        item.iSubItem = 0;        
        item.pszText = row[0];
        m_list.InsertItem (&item);
        for (int z = 1; z < counter; z++) {
            item.iSubItem = z;
            item.pszText = row[z];
            m_list.SetItem (&item);
        }

        i++;
    }
    
}


Этот метод будет использоваться для отображения в правой части окна структуры данных, полученных в результате запросе к базе данных.
Фактически, это и будет главное просмотровое окно программы, отображающие данные и структуру таблиц баз данных.


20. Теперь мы снова идем во вкладку «Resources» и добавляем новый ресурс – диалоговое окно. Это окно будет использоваться для создания новой базы данных. Мы вводим туда новое текстовое поле типа CEdit  и СStatic, для создания текстового заголовка: «New Database Name».  Создаем в Class Wizarde новый класс «CNewDatabaseDlg». К текстовому полю CEdit   подключаем переменную типа CString  - «m_newdatabase».  Эта переменная для задания нового имени вновь создаваемой базы данных.

21. Переопределяем метод этого класса OnOK() для исполнения запроса к MySQL серверу по созданию новой базы.

void CNewDatabase::OnOK()
{
            UpdateData(TRUE);
    CString sql="CREATE DATABASE ";
    sql +=m_newdatabase;
    ((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
    
    CDialog::OnOK();
}


22. Подключаем заголовочный файл нового диалогового «CreateNewTableDlg.h» к классу «CleftView.срр» для последующей обработки командой меню.


23. Теперь переходим опять во вкладку «Resources» и добавляем  новое диалоговое окно. На этот раз в нем будет окно для исполнения запросов к базе данных. Мы добавляем туда  следующие контролы: ССombox – сюда мы будем вводить SQL запрос, CListBox  - это будет форма для отображения списка доступных нам баз данных и CListCtrl  - в нем будут отображаться результаты SQL  запросов.  Итак, мы создаем 2 переменных класса:
CListBox m_listbox и  CListCtrl m_list.

24. Затем мы добавляем новый метод к этому классу диалога- void AddStr(). Этот метод будет получать строковую переменную, введенную в CComboBox . Далее код этого метода:

void CSqlQueryDlg::AddStr()
{

CComboBox *Box;

Box = (CComboBox *)(this->GetDlgItem(IDC_COMBO1));

Box->AddString(m_sql);
}



25. Теперь нам необходимо заполнить список базами данных, которыей находятся в данный момент на сервере MySQL. Для этого мы подключаем и переопределяем метод OnInitDialog(). В нем мы заполняем список CListBox, который буджет показываться при запуске этого окна.

BOOL CSqlQueryDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // TODO:  Add extra initialization here
    MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
    MYSQL_RES * my_res;
    MYSQL_ROW row;
    CString data_sql="SHOW DATABASES";
       ((CMysqloneApp*)AfxGetApp())->ExecuteSQL (data_sql);

    my_res = mysql_store_result(mysql);
    while (row = mysql_fetch_row (my_res)) {
        char buffer[255];
        strcpy (buffer, row[0]);
        m_listbox.AddString(_T(buffer));
    }

    mysql_free_result (my_res);

    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}


26. Затем, мы переопределяем метод OnOK() у этого класса, чтобы выполнить SQL запрос.


void CSqlQueryDlg::OnOK()
{
    UpdateData();

MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);

CString basename;
m_listbox.GetText (m_listbox.GetCurSel(), basename);
((CMysqloneApp*)AfxGetApp())->ChangeCurrentBase (basename);
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (m_sql);

m_list.DeleteAllItems ();


while(m_list.DeleteColumn(0));
MYSQL_RES * my_res;
MYSQL_ROW row;
mysql_query (mysql, m_sql);
my_res = mysql_store_result (mysql);

int cols = mysql_num_fields (my_res);
int counter ;
for (counter = 0; counter < cols; counter++) {
    m_list.InsertColumn (counter, "Data", LVCFMT_LEFT, 50);
}

counter = cols;
LVITEM item;
item.mask = LVIF_TEXT;
int i = 0;
while (row = mysql_fetch_row (my_res)) {
    item.iItem = i;
    item.iSubItem = 0;    
    item.pszText = row[0];
    m_list.InsertItem (&item);
    for (int z = 1; z < counter; z++) {
            item.iSubItem = z;
            item.pszText = row[z];
            m_list.SetItem (&item);
        }

        i++;

}

mysql_free_result (my_res);


//CDialog::OnOK();
}

Заметим, что  последняя строка кода закомментирована, чтобы OnOk() не закрывал это окно по завершению работы.
опубликовано
Добавить новыйПоиск
Добавить комментарий
Имя:
E-mail:
 
Веб-сайт:
Заголовок:
UBB-Код:
[b] [i] [u] [url] [quote] [code] [img] 
 
 
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch:
:(:shock::X:side::):P:unsure::woohoo::huh::whistle:;):s
:!::?::idea::arrow:
 
Security Image
Пожалуйста, введите проверочный код, который Вы видите на картинке.

Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved.

 
< Пред.   След. >