Click here to Skip to main content
11,637,415 members (63,321 online)
Click here to Skip to main content

Beginners Guide to Dialog Based Applications - Part Two

, 29 Jun 2000 377.5K 9.7K 132
Rate this:
Please Sign up or sign in to vote.
A step by step tutorial showing how to create your first Windows program using MFC.

Introduction

Dialog boxes are one of the primary methods that Windows programs use to display information and receive input from users. Therefore, in this tutorial, we are going to use a dialog based application to collect some information from the user. In the real life project, you will use this information somewhere else in the program or it will be stored in a database. But for this tutorial, we are only going to display information in a Message Box.

In this project, the user has to give his/her name and choose their favorite operating system and programming language. The user selects some of their favorite programming technologies and then submits the information by clicking on the Submit Button.

The information will be displayed in a Message Box, see below:

Creating a new Project and designing the dialog

Create a new dialog based application project called Dialog2, accepting the default settings in each step as we did in the last tutorial.

Delete the Cancel button and the text (TODO: Place dialog controls here), and change the Caption of the OK button to Close.

Drop a Button, Combo Box, two Edit Box controls, two List Box controls, six Static text controls and two Group Box into the dialog box, and arrange the controls as shown below.

Drop four Radio Buttons inside the first Group Box. Make sure to drop the Radio Button in sequence, one after another, and don't drop any other controls in between.

Drop three Check Boxes inside the second Group Box as shown below:

Customize the properties of controls

Change the Caption for each control as shown below. Check the Beginners Guide to Dialog Base Applications - Part One (previous tutorial) for full details on changing the ID and Caption for each control.

In the case of new controls Group Boxes, Radio Buttons and Check Boxes, the process of changing the captions and ID is similar to other controls (right click the mouse on the control and select Properties from the context menu).

Change the ID in Edit Properties for first Edit Box control to IDC_FIRSTNAME and the second Edit Box control to IDC_LASTNAME.

Change the ID in Combo Box Properties to IDC_TITLE. Click on Data in Combo Box Properties and populate the Data as shown below:

On Styles tab, change the Combo Box's Type to Drop List to stop the user from adding new titles. Position your mouse over the Combo Box button, then click. Another rectangle will appear. Use this rectangle to specify the size of the open Combo Box's List.

For the List Box on the left of the dialog box, change the ID to IDC_PROG_TECH and for the List Box on the right, change the ID to IDC_YOUR_FAVOURITE_TECH.

Check the Tab Stop option in Properties of the group box with Radio Buttons (Specifies that the user can move to this control with the TAB key)

Change the first Radio Button with caption Windows 95/98 Properties ID to IDC_WIN98 and check Group option (Specifies the first control of the group).

Make sure to check the Group option in the properties of the first control you drop into the dialog, after the last radio button. This implicitly marks the previous control (the last radio button) as the final one in the group.

Change the ID for the Windows NT/2000 Radio Button to IDC_WINNT. Change Unix ID to IDC_UNIX and Linux to IDC_LINUX.

For the second Group Box, change the ID for the Check Box with Caption Java to IDC_JAVA. Change the ID of Visual Basic Check Box to IDC_VISUAL_BASIC and change the ID of Visual CPP Check Box to IDC_VISUAL_CPP.

Change the ID for the Submit button to IDC_SUBMIT and the ID of the button with the Caption >> to IDC_SELECT and the ID of << button to IDC_DESELECT.

Assigning Member variables to Controls

Press Ctrl + W to start ClassWizard, or from the View menu, select ClassWizard. Select the Member Variables tab. Select the dialog class in the Class name: combo box; select CDialog2Dlg.

Assign m_strFirstName of type CString to IDC_FIRSTNAME, m_strLastName of type CString to IDC_LASTNAME, m_nTitle of type int to IDC_TITLE.

Assign m_bJava of type BOOL IDC_JAVA, m_bVisualBasic of type BOOL to IDC_VISUAL_BASIC, m_bVisualCpp of type BOOL to IDC_VISUAL_CPP.

Assign m_Win98 of type int to IDC_WIN98.

You will note that we only assign a variable to the first Radio Button. That is because Radio Buttons work in groups. Therefore, we can access the rest of the Radio Buttons through the first one. Each Radio Button represents one in a list of mutually exclusive options. When clicked, a Radio Button checks itself and un-checks the other Radio Button in the group. That is, of course, assuming that the Auto option has been checked in the Style tab in the properties of the Radio Button. The Auto option is checked by default.

Assign m_YourFavouriteTech of type CListBox to IDC_YOUR_FAVOURITE_TECH and m_ProgTech of type CListBox to IDC_PROG_TEACH.

In Class View tab, right click CDialog2Dlg class and select Add Member Variable. An Add Member Variable dialog box will appear. Add three member variables of type CString: m_strFullInfo, m_strOpertingSystem, m_strProgLanguage. Make sure to choose the Protected Access option.

Initializing Variables

Now that the variables are added, they must each be initialized. The ClassWizard has created code in the program that initializes the variables in the class constructor.

But in the case of m_nWin98 and m_nTitle, these values are initialized to -1, which means that if the program is built and run at this point, none of the radio buttons will be selected and the Title Combo Box will show an empty selection when the dialog box is first displayed.

Therefore, we need to change the values to 0 to select the first Radio Button and the first title. To do this, we need to edit the initialization code created by the ClassWizard in CDialog2Dlg class constructor. Double-click on the class constructor, the constructor function is displayed as shown below. Comment out m_nTitle and m_nWin98 which is generated by the ClassWizard and assign new values to the variables at the end of the constructor as shown below:

CDialog2Dlg::CDialog2Dlg(CWnd* pParent /*=NULL*/)
    : CDialog(CDialog2Dlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CDialog2Dlg)
    m_strFirstName = _T("");
    m_strLastName = _T("");
    m_bJava = FALSE;
    //m_nTitle = -1;
    m_bVisualBasic = FALSE;
    m_bVisualCpp = FALSE;
    //m_nWin98 = -1;
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent 
    // DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    
    m_nWin98 = 0;
    m_nTitle = 0;
    
}

Adding Member Functions

Right click CDialog2Dlg class and add member function for the Function Type.

Enter void and for the Function Declaration, type PopulateProgTech(). Make sure to choose Public option in Access as shown below.

We are going to use this function to populate the Programming Technologies List Box.

Type the code below:

void CDialog2Dlg::PopulateProgTech()
{
//Populate Programming Technologies List Box
    m_Prog_Tech.AddString("MFC");
    m_Prog_Tech.AddString("COM/DCOM");
    m_Prog_Tech.AddString("ADO");
    m_Prog_Tech.AddString("OLE DB");
    m_Prog_Tech.AddString("ASP");
    m_Prog_Tech.AddString("ATL");
}

Remember we used AddString() which is CListBox member function to add new text to List Box in the last tutorial.

Double click on the OnInitDialog() function in CDialog2Dlg class and call PopulateProgTech() member function just above the return statement as shown below.

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

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    // TODO: Add extra initialization here

    //Populate Programming Technologies List Box
    PopulateProgTech();  
    
    return TRUE;  // return TRUE  unless you set the focus to a control
}

Open ClassWizard, select Message Maps tab.

In Class name, select CDialog2Dlg, on Object IDs. Select IDC_SELECT, then choose BN_CLICKED from the Messages list, click on Add Function. Click OK, then click Edit Code. Add the code below to OnSelect() function.

void CDialog2Dlg::OnSelect() 
{
    // TODO: Add your control notification handler code here

    //Get the index of the selected item
    int nSelectted=m_ProgTech.GetCurSel();
        
    if (nSelectted != LB_ERR)       //Check for Selection
    {
        CString Sel;

        //Get the Selectted Text
        m_ProgTech.GetText(nSelectted,Sel);      

        //Add string to list to Favourite Technology
        m_YourFavouriteTech.AddString(Sel);      

        //Delete the Selectted item from the list of Techologies
        m_ProgTech.DeleteString(nSelectted); 
    }

}

Assuming you selected an item from the Technologies List Box, clicking on the >> Button will transfer the selected item to the Your Favorite Technologies List Box. OnSelect() function checks for selection first. Copy the text of the selected item into local variable Sel. Add this text to Your Favorite Technologies List Box and then delete the selected item from Technologies List Box.

Double click on >> Button. As soon as you do this, the Add Member Function dialog box will open as shown below.

Accept the default name OnDeselect() and type the code below.

void CDialog2Dlg::OnDeselect()
{
    // TODO: Add your control notification handler code here
    
    //Get the index of the selected item
    int nSelectted=m_YourFavouriteTech.GetCurSel(); 
    
    if (nSelectted != LB_ERR) //Check for Selection
    {
    CString Sel;
    
    //Get the Selectted Text    
    m_YourFavouriteTech.GetText(nSelectted,Sel);   

    //Add the deselectted technology to list to back Technology
    m_ProgTech.AddString(Sel);        
        
    //Delete the Selectted item from the list of Favourite Techologies
    m_YourFavouriteTech.DeleteString(nSelectted);  
    }

}

The function above transfers the selected item from Your Favorite Technologies List Box back to Technologies List Box (Deselected the item).

Double click on the Submit Button. Accept the default name OnSubmit() for new function and add the code below.

void CDialog2Dlg::OnSubmit() 
{
    // TODO: Add your control notification handler code here
    CString strTitle;
    int nReturnValue;
    
    m_strProgLanguage="Programming Languages your prefer \n" ;

    UpdateData(); //Transfer data from controls to variables
    
    //Get the text of the selected radio button
    GetDlgItem(IDC_WIN98+m_nWin98)->GetWindowText(m_strOpertingSystem);
    
    //Get the text of the checked Check Boxes
    
    if(m_bJava)
        m_strProgLanguage+="Java\n "  ;
    
    if(m_bVisualBasic)
        m_strProgLanguage+="Visual Basic\n "  ;
    
    if(m_bVisualCpp)
        m_strProgLanguage+="C++/Visual C++\n "  ;
    
    //get currently selected text of the Combo Box
    
    nReturnValue=GetDlgItemText(IDC_TITLE, strTitle);
    
    m_strFullInfo = "You are "+strTitle + " "+m_strFirstName + 
                    " "+ m_strLastName;
    
    UpdateData(FALSE);  //Transfer data from variables to controls
    
    CString Sel;
    m_strSelectedTech="";

    //Get number of items in the list box
    int nCount = m_YourFavouriteTech.GetCount();  
    
    if(nCount > 0) //Check for empty list box
    {
        for(int i=0; i<nCount; i++) 
        {

            m_YourFavouriteTech.GetText(i, Sel);
    
            m_strSelectedTech+=Sel + "\n";
        }
    }

    m_strFullInfo=m_strFullInfo+"\n"+ m_strProgLanguage +"\n" 
        + "favourite technology\n "+m_strSelectedTech+
        "\nand your favourite operating System is \n"
        +m_strOpertingSystem;

    MessageBox(m_strFullInfo);   //Show the information in Message Box
    
    
}

OnSubmit() collects all user information and puts them into Message Box.

Build and run your program

So far you have learned how to:

  • Add, edit and customize Button, Edit Box Control, Combo Box, List Box, Group Box, Check Box, Radio Buttons.
  • Use a ClassWizard to assign member variables to controls.
  • Add member variables.
  • Add member functions.
  • Use item data,
  • Select items.
  • Determine which item has been selected.
  • Get item information.
  • Handle CButton notification.

Multi-Internet Search Engine

Introduction

For this part of the tutorial, we are going to build a simple but very useful program: a Multi-Internet Search Engine. Realistically, it is only a program which enables the user to access a number of Internet search engines like Altavista, Yahoo, ... without the hassle of remembering the address of each search engine. All the user has to do is select a search engine and type what s/he is trying to find out about, then click Search Button. Below, the user tries to use Altavista to find some information about Physics.

Creating a new Project, designing and customizing the dialog

Start by creating a new Dialog based application called Search_me as we did before.

Delete the Cancel button and the text (TODO: Place dialog controls here). Resize your dialog box to about 300 x 70, change the caption of OK button to Close.

Drop Button, Edit Box, Combo Box and two Static text controls into the dialog box. Change the static text Caption to Search Engine and Search for: Change the ID for the Combo Box to IDC_ENGINE.

Click on Data in Combo Box Properties and populate the data as shown below. Remember to press Ctrl + Enter after each entry.

On the Styles tab, change the Combo Box's Type to Drop List to make sure that the user can't add new search engine.

Position your mouse over the Combo Box button, then click. Another rectangle will appear. Use this rectangle to specify the size of the open Combo Box's List.

Change ID for Edit Box to IDC_SEARCHFOR.

Change the Caption for button to Search and the ID to IDC_SEARCH. Use the ClassWizard to assign member variables m_strSearchFor of type CString for Edit Box and m_nEngine of type int for the Combo Box.

Add member variable of type CString named m_strSearch to CSearch_meDlg class.

Press Ctrl + W to start the ClassWizard, select Message Maps tabs. In Class name, select CSearch_meDlg, on Object IDs select IDC_ENGINE, then choose BN_CLICKED from Messages list. Click on Add function, accepting the default name OnSearch(), then click Edit Code. Then type the code below.

void CSearch_meDlg::OnSearch() 
{
    // TODO: Add your control notification handler code here
    CString strEngine;
    int nReturnValue;

    UpdateData();         //Transfer data from controls to variables
    
    m_strSearch = m_strSearchFor;
    //get currently selected text
    nReturnValue=GetDlgItemText(IDC_ENGINE, strEngine); 
    
    UpdateData(FALSE);      //Transfer data from variables to controls
    
    if(nReturnValue>0)      //Check for Search engine selection
    {
        if(strEngine=="Yahoo")
        {
            m_strSearch = "http://search.yahoo.com/search?p=" 
                                + m_strSearch;
            ShellExecute(NULL, "open", m_strSearch, 
                        NULL,NULL,SW_SHOWDEFAULT);
        }

        else if(strEngine=="Altavista")
        {
            m_strSearch = 
                "http://www.altavista.digital.com/cgi-bin/query?" + "
                pg=q&what=web&fmt=.&q=" + m_strSearch;
            ShellExecute(NULL, "open", m_strSearch,
                NULL,NULL,SW_SHOWDEFAULT);
        }

        else if(strEngine=="Excite")
        {
            m_strSearch = "http://www.excite.com/search.gw?trace=a&search="
                                +m_strSearch;
            ShellExecute(NULL, "open", m_strSearch,
                NULL,NULL,SW_SHOWDEFAULT);
        }

        else if(strEngine=="Askjeeves")
        {
            m_strSearch = "http://www.askjeeves.com/AskJeeves.asp?ask="
                                +m_strSearch;
            ShellExecute(NULL, "open", m_strSearch,
                NULL,NULL,SW_SHOWDEFAULT);
        }


    }

}

We used the ShellExecute() function to open the Internet Client Internet Explorer or any other default Internet client program. Check MSDN Library file for more information on ShellExecute().

Edit the constructor of CSearch_meDlg class and change the value of m_nEngine from -1 to 0 as we did previously, to make sure that when the Search_me dialog box is first displayed, Altavista will be selected on Combo Box.

Build and run your program

If you like the idea of this program, you could add more search engines to Search_me program. The best way of adding new search engines is to use Internet Explorer or any Internet Client to access the particular search engine you wish to add to do a simple search. Then copy the address from Explorer's Combo Box which is a query string (information that is passed to the server in the form of a name/value pair) appended to URL with a question mark, '?'. Use the address from the Explorer's Combo Box which you just copied into the program.

For example, if you do a search for Books using excite search engine, the result page will have address of http://search.excite.com/search.gw?search=Physics which is a URL ( http://search.excite.com/search.gw), '?' and query string (search=Books). All you need to do is replace Physics with m_strSearch.

I hope you found this tutorial enjoyable.

Further Reading

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Dr. Asad Altimeemy
Web Developer
United Kingdom United Kingdom
No Biography provided

You may also be interested in...

Comments and Discussions

 
Generalhi!!! Pin
AinJheL_mi28-Jun-06 0:15
memberAinJheL_mi28-Jun-06 0:15 
GeneralDoes not execute Pin
pradeep paul10-Jun-05 4:32
susspradeep paul10-Jun-05 4:32 
Generaldifferent in Visual Studio 7.1 Pin
filius31-May-05 2:08
memberfilius31-May-05 2:08 
General7.1: checkbox Pin
filius7-Jun-05 2:32
memberfilius7-Jun-05 2:32 
Generalquestion for beginners guide to dialog based applications-part two Pin
jinshi23-Jan-05 5:01
memberjinshi23-Jan-05 5:01 
Generaluse button to link a combo box to another dialog Pin
jinshi22-Jan-05 20:35
memberjinshi22-Jan-05 20:35 
GeneralStatic Frames Pin
bamamojo12-May-04 12:07
memberbamamojo12-May-04 12:07 
GeneralCombo Box Pin
Anonymous28-Mar-04 21:27
sussAnonymous28-Mar-04 21:27 
GeneralRe: Combo Box Pin
allmer1-Apr-04 10:56
memberallmer1-Apr-04 10:56 
GeneralRe: Combo Box Pin
jinshi22-Jan-05 20:40
memberjinshi22-Jan-05 20:40 
GeneralReflecting dialog box values in the object which called it Pin
mymauve2110-Mar-04 0:40
membermymauve2110-Mar-04 0:40 
Generalvoice conferencing Pin
saechi17-Feb-04 0:01
membersaechi17-Feb-04 0:01 
Questionhttp://latina.ceroline.info/ Pin
http://latina.ceroline.info/4-Dec-07 1:06
susshttp://latina.ceroline.info/4-Dec-07 1:06 
QuestionHow to know that dialog window is opened Pin
Vladimir S10-Dec-03 21:57
memberVladimir S10-Dec-03 21:57 
GeneralNeed help with multiple dialogs Pin
HybridLlama24-Oct-03 17:47
memberHybridLlama24-Oct-03 17:47 
Generalhelp&#161;&#161; my modal dialog not showed Pin
remius28-Sep-03 4:29
sussremius28-Sep-03 4:29 
GeneralMember variables Pin
DetectorElec25-Aug-03 9:49
memberDetectorElec25-Aug-03 9:49 
GeneralMultiple modal dialog boxes. Pin
Deepak Samuel21-Jul-03 5:05
memberDeepak Samuel21-Jul-03 5:05 
GeneralRe: Multiple modal dialog boxes. Pin
Cambalindo25-Aug-03 10:50
memberCambalindo25-Aug-03 10:50 
GeneralAdding to a CListbox before show Pin
Jamie Kenyon21-May-03 1:50
memberJamie Kenyon21-May-03 1:50 
GeneralRe: Adding to a CListbox before show Pin
Anonymous20-Jul-05 3:25
sussAnonymous20-Jul-05 3:25 
GeneralMonitoring variables in dialog box Pin
alrobin30-Apr-03 11:04
memberalrobin30-Apr-03 11:04 
GeneralRe: Monitoring variables in dialog box Pin
digitalmythology10-Dec-06 16:45
memberdigitalmythology10-Dec-06 16:45 
QuestionHow can I change color of dialog box Pin
edv23-Apr-03 2:34
memberedv23-Apr-03 2:34 
Generalwhy I have to use nReturnValue as fellowing nReturnValue=GetDlgItemText(IDC_ENGINE, strEngine); Pin
goldust9-Apr-03 13:54
membergoldust9-Apr-03 13:54 
GeneralPlease explain GetItemDlg() in getting value from radiobutton group Pin
goldust9-Apr-03 12:35
membergoldust9-Apr-03 12:35 
GeneralRe: Please explain GetItemDlg() in getting value from radiobutton group Pin
vikas amin27-Aug-05 21:22
membervikas amin27-Aug-05 21:22 
GeneralRe: Please explain GetItemDlg() in getting value from radiobutton group Pin
Anonymous8-Sep-05 4:32
sussAnonymous8-Sep-05 4:32 
GeneralUpdate Menu items in Dialog-based application Pin
gameover29-Jan-03 2:32
membergameover29-Jan-03 2:32 
Generaltwo modal dialogs Pin
Luis Reina3-Sep-02 23:29
memberLuis Reina3-Sep-02 23:29 
GeneralRe: two modal dialogs Pin
Luis Reina4-Sep-02 1:09
memberLuis Reina4-Sep-02 1:09 
GeneralError with m_strSelectedTech="" Pin
Anonymous2-Jul-02 12:46
memberAnonymous2-Jul-02 12:46 
GeneralRe: Error with m_strSelectedTech="" Pin
Gean4-Sep-02 2:48
memberGean4-Sep-02 2:48 
GeneralTHankyou Pin
Anonymous20-Jun-02 6:10
memberAnonymous20-Jun-02 6:10 
GeneralOverriding OnCancel() Pin
JoeSox14-Jun-02 3:32
memberJoeSox14-Jun-02 3:32 
Questionis there an unwritten law that all tutorials must be incorrect? Pin
spoongirl6-May-02 8:08
memberspoongirl6-May-02 8:08 
AnswerRe: is there an unwritten law that all tutorials must be incorrect? Pin
Anonymous31-Oct-03 8:19
sussAnonymous31-Oct-03 8:19 
GeneralVC++ Pin
Sumesh27-Mar-02 6:50
memberSumesh27-Mar-02 6:50 
QuestionHow to Open a Window and display a bitmap? Pin
SMer19-Mar-02 4:02
memberSMer19-Mar-02 4:02 
QuestionHow to set Windows texts align at both left and right? Pin
Anonymous6-Mar-02 12:36
memberAnonymous6-Mar-02 12:36 
GeneralDialog Based Application Pin
Stambroise18-Feb-02 3:31
memberStambroise18-Feb-02 3:31 
GeneralRe: Dialog Based Application Pin
rrrado6-Mar-02 1:45
memberrrrado6-Mar-02 1:45 
GeneralRe: Dialog Based Application Pin
Prashant Singh Sisodiya26-Sep-07 1:31
memberPrashant Singh Sisodiya26-Sep-07 1:31 
GeneralGood and practical Pin
Johnson10-Dec-01 20:46
memberJohnson10-Dec-01 20:46 
Generalneed help with MFC program Pin
Gustav31-Jul-01 5:48
memberGustav31-Jul-01 5:48 
GeneralRe: need help with MFC program Pin
Anonymous31-Jul-03 21:17
sussAnonymous31-Jul-03 21:17 
GeneralImporting existing Dialog interfaces into a new SDI application. Pin
Kimball M. Rudeen25-May-01 13:02
memberKimball M. Rudeen25-May-01 13:02 
GeneralI need help with SIMPLE functions Pin
Tucker12-Mar-01 7:42
memberTucker12-Mar-01 7:42 
GeneralRe: I need help with SIMPLE functions Pin
Chris Losinger12-Mar-01 8:11
memberChris Losinger12-Mar-01 8:11 
GeneralRe: I need help with SIMPLE functions Pin
L33tHax0r8D25-Jun-01 3:21
memberL33tHax0r8D25-Jun-01 3:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150728.1 | Last Updated 30 Jun 2000
Article Copyright 2000 by Dr. Asad Altimeemy
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid