Avatar billede alex_sleiborg Nybegynder
13. marts 2006 - 20:11 Der er 23 kommentarer og
1 løsning

Lave en openfiledialog i c++ konsol

Hey. Jeg er ved at lave et lille konsol program i c++. Jeg har lavet en lille menu udfra noget kode, som jeg har fået af bertel brander.

Her er et link til menuen

http://home20.inet.tele.dk/midgaard/snip/menu.html

Jeg skal gerne have lavet sådan at menu'en viser feks. roden af c: drevet, og man kan klikke på en mappe så bliver indholdet af mappen så vist. Og til sidst når man har fundet den fil man skal bruge,, så klikker man på den, Og så returnerer den, den fulde sti på filen. Ligesom en openfiledialog i c#.

Nogen der har nogle links til noget, eller der kan hjælpe mig. Jeg skal nok også have skåret det ud i pap. Jeg er nemlig ikke så god til c++
Avatar billede bertelbrander Novice
13. marts 2006 - 20:53 #1
Jeg kunne godt lave det vha. FindFirstFile/FindNext, men var det ikke lettere at bruge en rigtig GetOpenFileName?
Avatar billede alex_sleiborg Nybegynder
13. marts 2006 - 20:54 #2
Jo men kan man det??? Kender ikke c++ specielt godt. Det er jo en konsol app.
Avatar billede bertelbrander Novice
13. marts 2006 - 20:59 #3
Det burde der ikke være noget problem i, dialog-boxen vil narturligvis komme op som en normal windows dialogbox.

Prøv at kikke på funktionen OnFileOpen:
http://home20.inet.tele.dk/midgaard/snip/texteditor.html

MainWindow og InstanceHandle erstatter du bare med 0, resultatet gemmes i CurrentFileName.
Avatar billede alex_sleiborg Nybegynder
13. marts 2006 - 21:04 #4
Det er noget der skal laves i skolen. Det skal laves 100% i konsol. Så det duer ikke med at åbne nogle windows vinduer, det er godt nok det er lidt træls
Avatar billede bertelbrander Novice
13. marts 2006 - 21:09 #5
Jeg prøver at lave noget senere på aftenen.
Er det Ok at bruge windows.h og de konsol funktioner der findes der?
Avatar billede alex_sleiborg Nybegynder
13. marts 2006 - 21:09 #6
Jep selvfølgelig
Avatar billede bertelbrander Novice
14. marts 2006 - 00:07 #7
Du kan starte med nedenstående.
Der er (mindst) to mangler:
1: Den kan kun vise 20 filer eller mapper, hvis du vil have flere skal der laves noget scrolling
2: Man skriver alle mappe eller fil - navne hver gang, det giver noget flimmer.

#include <windows.h>
#include <vector>
#include <string>
#include <string.h>
#include <iostream>

static const size_t MAX_NUM_FILE = 20;
static const HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
static const HANDLE StdIn = GetStdHandle(STD_INPUT_HANDLE);

void GotoXY(int x, int y);
void ClearScreen();
WORD GetChar();

class FileInfoClass
{
public:
  FileInfoClass(const std::string& aName, bool aIsDir)
      : Name(aName), IsDir(aIsDir)
  {}
  std::string Name;
  bool IsDir;
};

bool operator < (const FileInfoClass& lhs, const FileInfoClass& rhs)
{
  if(lhs.IsDir && !rhs.IsDir)
      return true;
  if(!lhs.IsDir && rhs.IsDir)
      return false;
  return stricmp(lhs.Name.c_str(), rhs.Name.c_str()) < 0;
}

std::vector <FileInfoClass> FileInfoList;

void Scan(const std::string &aDir, const char *aPattern)
{
  FileInfoList.clear();
  WIN32_FIND_DATA FindFileData;
  std::string temp = aDir + "\\" + aPattern;
  HANDLE FindHandle = FindFirstFile(temp.c_str(), &FindFileData);
  if(FindHandle != INVALID_HANDLE_VALUE)
  {
      do
      {
        if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
        {
            FileInfoList.push_back(FileInfoClass(FindFileData.cFileName, false));
        }
      }
      while(FindNextFile(FindHandle, &FindFileData) && FileInfoList.size() < MAX_NUM_FILE - 1);
      FindClose(FindHandle);
  }

  temp = aDir + "\\*.*";
  FindHandle = FindFirstFile(temp.c_str(), &FindFileData);
  if(FindHandle != INVALID_HANDLE_VALUE)
  {
      do
      {
        if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
            strcmp(FindFileData.cFileName, ".") &&
            strcmp(FindFileData.cFileName, ".."))
        {
            FileInfoList.push_back(FileInfoClass(FindFileData.cFileName, true));
        }
      }
      while(FindNextFile(FindHandle, &FindFileData) && FileInfoList.size() < MAX_NUM_FILE - 1);
      FindClose(FindHandle);
  }
  if(aDir.find('\\') != std::string::npos)
  {  // add a .. folder if we are not at the root, only needed as we might not have room for all entries
      FileInfoList.push_back(FileInfoClass("..", true));
  }

  std::sort(FileInfoList.begin(), FileInfoList.end());
}

void GetFileName(std::string& aFullName)
{
  std::string CurrentDir = "C:";
  const char *Ext = "*.txt";
  CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
  GetConsoleScreenBufferInfo(StdOut, &ConsoleScreenBufferInfo);

  WORD DefAttrib = ConsoleScreenBufferInfo.wAttributes;
  Scan(CurrentDir, Ext);
  unsigned int Idx = 0;

  while(1)
  {
      unsigned int n;
      ClearScreen();
      for(n = 0; n < FileInfoList.size(); n++)
      {
        GotoXY(1, n + 1);
        if(FileInfoList[n].IsDir)
        {
            if(Idx == n)
            {
              SetConsoleTextAttribute(StdOut, FOREGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
            }
            else
            {
              SetConsoleTextAttribute(StdOut, FOREGROUND_GREEN);
            }
        }
        else
        {
            if(Idx == n)
            {
              SetConsoleTextAttribute(StdOut, FOREGROUND_BLUE | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
            }
            else
            {
              SetConsoleTextAttribute(StdOut, FOREGROUND_BLUE);
            }
        }
        std::cout << FileInfoList[n].Name;
      }
      SetConsoleTextAttribute(StdOut, DefAttrib);
      switch(GetChar())
      {
      case VK_DOWN:
        if(Idx < FileInfoList.size() - 1)
            Idx++;
        break;
      case VK_UP:
        if(Idx)
            Idx--;
        break;
      case VK_RETURN:
        if(FileInfoList[Idx].IsDir)
        {
            if(FileInfoList[Idx].Name != "..")
            {
              CurrentDir += std::string("\\") + FileInfoList[Idx].Name;
            }
            else
            {
              std::string::size_type pos = CurrentDir.rfind('\\');
              if(pos != std::string::npos)
              {
                  CurrentDir = CurrentDir.substr(0, pos);
              }
            }
            Scan(CurrentDir, Ext);
            Idx = 0;
        }
        else
        {
            ClearScreen();
            aFullName = CurrentDir + "\\" + FileInfoList[Idx].Name;
            return;
        }
        break;
      }
  }
}

int main()
{
  std::string Name;
  GetFileName(Name);
  std::cout << "You have selected: " << Name << std::endl;
}

void GotoXY(int x, int y)
{
  COORD c;
  c.X = (short )x;
  c.Y = (short )y;
  SetConsoleCursorPosition(StdOut, c);
}

void ClearScreen()
{
  short i;
  CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
  GetConsoleScreenBufferInfo(StdOut, &ConsoleScreenBufferInfo);
  SMALL_RECT Pos = ConsoleScreenBufferInfo.srWindow;

  DWORD D;

  for(i = Pos.Top; i <= Pos.Bottom; i++)
  {
    COORD C;
    C.X = Pos.Left;
    C.Y = i;
    FillConsoleOutputCharacter(StdOut, ' ', Pos.Right - Pos.Left, C, &D);
    FillConsoleOutputAttribute(StdOut, 0, Pos.Right - Pos.Left, C, &D);
  }
  GotoXY(0, 0);
}

WORD GetChar()
{
  DWORD NumEventsRead;
  INPUT_RECORD InputRecord;

  while(1)
  {
    while(!ReadConsoleInput(StdIn, &InputRecord, 1, &NumEventsRead))
      Sleep(50);
    if(InputRecord.EventType & KEY_EVENT && InputRecord.Event.KeyEvent.bKeyDown)
    {
      if(InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_CONTROL &&
        InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_MENU  &&
        InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_SHIFT)
      {
        return InputRecord.Event.KeyEvent.wVirtualKeyCode;
      }
    }
  }
}
Avatar billede alex_sleiborg Nybegynder
14. marts 2006 - 18:37 #8
Kanon det ser rigtigt godt ud. Hvis jeg gerne vil have skrevet noget tekst, ovenfor de valg der er i en sub menu. Nu tænker jeg på det her eksempel

http://home20.inet.tele.dk/midgaard/snip/menu.html

Burde jeg ikke kunne gøre nogenlunde således

menu_item const langues_menu[] =
{
    text_out(NORM_ATTR, -5, -8, "test test test");

    {"Dansk", main_menu, NULL},
    {"English", main_menu, NULL},
    {NULL, NULL, NULL}
};

Får dog compiler fejl, så det kan ikke være rigtigt
Avatar billede bertelbrander Novice
14. marts 2006 - 19:37 #9
langues_menu er en variabel, delen inden for { } er definering af variablen. Du kan ikke mixe dette med kode, text_out er kode.

Vil du have en text til at stå over hver submenu?
Avatar billede alex_sleiborg Nybegynder
14. marts 2006 - 19:42 #10
Der står noget øverst når programmet kører, der skal stå der hele tiden. Og så skal der stå noget forskelligt til hver submenu
Avatar billede bertelbrander Novice
14. marts 2006 - 19:51 #11
Jeg prøver at strikke noget sammen.
Avatar billede alex_sleiborg Nybegynder
14. marts 2006 - 19:57 #12
Jeg skal vel have lavet noget om her

for(i = 0; menu[i].title; i++)
    {
      if(i == state)
        text_out(INVR_ATTR, 0, i, menu[i].title);
      else
        text_out(NORM_ATTR, 0, i, menu[i].title);
    }

Så der kommer en text_out mere. Og så skal mine menu variabler vel laves om, så man også skriver hvad der skal stå ovenover
Avatar billede bertelbrander Novice
14. marts 2006 - 20:23 #13
Prøv denne:
#include <windows.h>
#include <stdlib.h>

typedef struct menu_item
{
  const char *title;
  const struct menu_struct *submenu;
  void(*function)(void);
}menu_item;

typedef struct menu_struct
{
  const char *header;
  const struct menu_item *menu;
}menu_struct;

HANDLE Console;
HANDLE ConsoleIn;

#define NORM_ATTR (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define INVR_ATTR (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
#define EMPTY_LINE "                                                                                "

void text_out(short attr, int x, int y, const char *text)
{
  DWORD Dummy;
  COORD Coord;
  SetConsoleTextAttribute(Console, NORM_ATTR);
  Coord.X = x + 5;
  Coord.Y = y + 5;
  SetConsoleCursorPosition(Console, Coord);
  WriteConsole(Console, EMPTY_LINE, strlen(EMPTY_LINE), &Dummy, 0);

  SetConsoleCursorPosition(Console, Coord);
  SetConsoleTextAttribute(Console, attr);
  WriteConsole(Console, text, strlen(text), &Dummy, 0);
}

void show_status(const char *msg)
{
  text_out(NORM_ATTR, 0, 12, msg);
}

int get_key(void)
{
  INPUT_RECORD Input;
  DWORD NumRead;
  do
  { /* Wait for key release */
    ReadConsoleInput(ConsoleIn, &Input, 1, &NumRead);
  }
  while(Input.EventType != KEY_EVENT && Input.Event.KeyEvent.bKeyDown);

  do
  { /* Read The Key */
    ReadConsoleInput(ConsoleIn, &Input, 1, &NumRead);
  }
  while(Input.EventType != KEY_EVENT && !Input.Event.KeyEvent.bKeyDown);
  return Input.Event.KeyEvent.wVirtualKeyCode;
}

#define DUMMY_FUNC(name) \
static void name(void)          \
{                        \
  show_status(#name);    \
}

DUMMY_FUNC(func_11)
DUMMY_FUNC(func_21)
DUMMY_FUNC(func_22)
DUMMY_FUNC(func_231)
DUMMY_FUNC(func_232)
DUMMY_FUNC(func_233)

void exit_func(void)
{
  SetConsoleTextAttribute(Console, NORM_ATTR);
  exit(0);
}

menu_item const pb_list_menu[] =
{
  {"Ole",  NULL, func_231},
  {"Peter", NULL, func_232},
  {"Poul",  NULL, func_233},
  {"Back",  NULL, NULL},
  {NULL,    NULL, NULL}
};

menu_struct pb_list_struct =
{
  "PB - List", pb_list_menu
};

menu_item const phonebook_menu[] =
{
  {"AddEntry", NULL, func_11},
  {"List",    &pb_list_struct, NULL},
  {"Back",    NULL, NULL},
  {NULL,      NULL, NULL}
};

menu_struct const phonebook_struct =
{
  "PhoneBook", phonebook_menu
};

menu_item const sub_menu_2[] =
{
  {"New SMS", NULL, func_21},
  {"List",    NULL, func_22},
  {"Back",    NULL, NULL},
  {NULL,      NULL, NULL}
};

menu_struct const sub_menu_2_struct =
{
  "Sub Menu", sub_menu_2
};

menu_item const main_menu[] =
{
  {"PhoneBook", &phonebook_struct, NULL},
  {"SMS",      &sub_menu_2_struct, NULL},
  {"Exit",      NULL,          exit_func},
  {NULL,        NULL,          NULL}
};

menu_struct const main_menu_struct =
{
  "Main Menu", main_menu
};

void exec(menu_struct const * menu);

void clear_menu_window(void)
{
  int i;
  for(i = 0; i < 15; i++)
  {
    text_out(NORM_ATTR, 0, i, "");
  }
}

int main(void)
{
  int i;
  DWORD Dummy;
  COORD Coord;
  Console = GetStdHandle(STD_OUTPUT_HANDLE);
  ConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
  SetConsoleMode(ConsoleIn, 0);

  SetConsoleTextAttribute(Console, NORM_ATTR);
  Coord.X = 1;
  Coord.Y = 1;
  SetConsoleCursorPosition(Console, Coord);

  for(i = 0; i < 80; i++)
    WriteConsole(Console, EMPTY_LINE, strlen(EMPTY_LINE), &Dummy, 0);

  text_out(NORM_ATTR, -4, -4, "Simple menu demo Press UP/Down, Enter to select");

  exec(&main_menu_struct);

  SetConsoleTextAttribute(Console, NORM_ATTR);
  return EXIT_SUCCESS;
}

/* This is the main menu executer, it will call itself to execute submenus */
void exec(menu_struct const * menu)
{
  int ch;
  int i;
  int state = 0;
  clear_menu_window();
  do
  {
    text_out(NORM_ATTR, -2, -2, menu->header);
    /* I'm lazy so I'll update the complete menu each time */
    for(i = 0; menu->menu[i].title; i++)
    {
      if(i == state)
        text_out(INVR_ATTR, 0, i, menu->menu[i].title);
      else
        text_out(NORM_ATTR, 0, i, menu->menu[i].title);
    }
    ch = get_key();
    switch(ch)
    {
      case VK_RETURN:  /* Enter */
        if(menu->menu[state].function)
          menu->menu[state].function();
        else if(menu->menu[state].submenu)
        { /* It's a submenu */
          exec(menu->menu[state].submenu);
          clear_menu_window();
        }
        else
        { /* It is a back menu item */
          return;
        }
        break;
      case VK_UP:
        if(state != 0)
          state--;
        break;
      case VK_DOWN:
        if(menu->menu[state + 1].title)
          state++;
        break;
    }
  }
  while(1);
}
Avatar billede alex_sleiborg Nybegynder
14. marts 2006 - 21:33 #14
Arr ja sådan kan man jo gøre. Må jeg lige spørge om en sidste ting, så skal du nok få point. Hvis du altså vil have dem

Når jeg i min menu gerne vil have den til at vise den filedialog, hvordan kalder jeg så den funktion???

Jeg har prøvet således

menu_item const main_menu[] =
{
  {"FileDialog", NULL, GetFileName(Name)},
  {"Afslut", NULL, exit_func},
  {NULL,      NULL, NULL}
};
Avatar billede bertelbrander Novice
14. marts 2006 - 21:54 #15
Du bliver nok nødt til at lave en wrapper funktion:

void GetFileNameWrapper(void)
{
  GetFileName(Name);
}

Og bruge wrapperen fra menu'en.
Avatar billede alex_sleiborg Nybegynder
14. marts 2006 - 22:04 #16
Jo nu virker det nogenlunde. Resten tror jeg godt jeg kan klare. Du må have 1000 tak for hjælpen. Smid et svar.

Må jeg skrive hvis der er noget der lige driller lidt???
Avatar billede bertelbrander Novice
14. marts 2006 - 22:30 #17
Jeg samler ikke på point.
Du skriver bare igen hvis der opstår problemer.
Avatar billede alex_sleiborg Nybegynder
15. marts 2006 - 15:45 #18
Hmm så er der opstået problemmer. :) Hehe. Jeg får ingen compiler fejl, men min menu ser lidt mærkelig ud. Nogle af menu'erne vil jeg have flyttet lidt længere ned, da der skal stå noget mere tekst. Det har jeg gjort på følgende måde

Du får lige lidt af min kode

typedef struct menu_struct
{
  int x; //Har lavet en variabel her
  const char *header;
  const struct menu_item *menu;
}menu_struct;

Og videre

menu_struct const langues_menu_struct =
{
  0, "V\x91lg Sprog",langues_menu //Her har jeg valgt nul, den skal ikke længere ned //af
};

Her + jeg så, så burde jeg kunne styre de enkelte menu'er??? Eller hvad

for(i = 0; menu->menu[i].title; i++)
    {
      if(i == state)
        text_out(INVR_ATTR, 0, i - menu[i].x, menu->menu[i].title);
      else
        text_out(NORM_ATTR, 0, i, menu->menu[i].title);
    }

Det virker faktisk. Men det hele kommer til at stå mærkeligt, når jeg kører op og ned i menu'erne. Kan du lige gennemskue hvad jeg gør galt
Avatar billede bertelbrander Novice
15. marts 2006 - 20:34 #19
Mangler du ikke at trække menu[i].x fra i else delen?
Avatar billede alex_sleiborg Nybegynder
15. marts 2006 - 22:36 #20
Jo det gjorde jeg også til at starte med. Men så stod menu'en forskudt hele tiden.
Du må sige til hvis du vil have noget kode
Avatar billede bertelbrander Novice
16. marts 2006 - 00:15 #21
Skal det ikke være:
menu->x;
i stedet for:
menu[i].x

Ellers post hele koden (eller send en email).
Avatar billede alex_sleiborg Nybegynder
14. december 2006 - 11:46 #22
Smid et svar bertel... Jeg fik det til at virke, mange tak for det:)
Avatar billede bertelbrander Novice
14. december 2006 - 20:11 #23
Jeg samler ikke på point.
Avatar billede alex_sleiborg Nybegynder
15. december 2006 - 08:28 #24
Okay. Så lukker jeg. Mange tak for de gode svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester