Cls nie działa w konsolowej aplikacji (CodeBlocks) win8.1

Witam, polecenie cls nie działa w moim mini konsolowym programie(nie działa też w innych programach,a przedtem działało)

program:

http://wklej.to/qrnNi

Inne pliki:

https://www.sendspace.com/file/9g09ci

Czym mogę zastąpić to polecenie, lub jak mogę sprawić by  cls znowu działało?

*Mój system to windows 8.1 , program to najnowsza wersja codeblocks., uczę się programowania w c++

Używanie system() jest słabym pomysłem. Pod Windowsem zapisy do konsoli wykonuje się funkcją WriteConsoleOutput i pochodnymi (czyszczenie łatwo wykonać sekwencją GetConsoleScreenBufferInfo/FillConsoleOutputCharacter/SetConsoleCursorPosition). Pod Linuksem większość terminali zaakceptuje write(1,"\E[H\E[2J",7) jako czyszczenie.

Dziękuje za pomoc, lecz jestem nowy w c ++(dopiero zaczynam(1dzień). CLS wydawał się prostym poleceńem na początek, niestety nie wiem jak wprwadzić twoje polecenia(chyba trzeba jakieś dodatkowe biblioteki)

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

Header: Wincon.h (include Windows.h)

Library: Kernel32.lib

Czyli domyślnie w VS wystarczy dołączyć windows.h i już. Wykukanie sposobu użycia to dobra wprawka w nauce języka. Co do system jeszcze - system uruchamia dodatkowy proces. To strzelanie z armaty do komara.

Trochę dziwne, że system(“cls”); Ci nie działa. W każdym razie i tak ten sposób czyszczenia nie jest najlepszy ze względów wydajnościowych (w przypadku początkujących może być akceptowalny, ale potem powinno się z tego „wyrosnąć” :wink: )

Jeśli wystarczy Ci nadpisywać tę samą linię, to możesz użyć \r

cout << "\r" << i;

Znak __ służy do wprowadzania znaków specjalnych (jeśli chciałbyś mieć znak __, to musisz wpisać \)

\r oznacza powrót karetki, czyli przesunięcie kursora na początek wiersza. Zauważ, że nie użyłem endl, który powoduje przejście do następnej linii, ponieważ przejście do następnego wiersza i przesunięcie się na jego początek nie dałoby za wiele :wink:

Jednak \r nie usunie zawartości wiersza, więc jeśli to co będziesz wypisywał, będzie krótsze od tego co było w wierszu to zostaną Ci końcowe znaki ze starej zawartości, możesz temu zaradzić wypisując trochę spacji i ponownie wrócić na początek wiersza

cout << "\r \r" << i;

Trzeba jeszcze wiedzieć o czymś takim jak buforowanie. Otóż wypisywany tekst nie musi od razu pojawiać się na konsoli, tylko być buforowany i dopiero jak zbierze się większa ilość jest wysyłany na konsolę, więc w niektórych implementacjach taki program może przez dłuższy czas nic nie wyświetlić.

Żeby wymusić opróżnienie bufora można użyć flush

cout << "\r \r" << i << flush;

endl oprócz zakończenia linii, również wymusza opróżnienie bufora, więc linia zakończona endl na pewno się wypisze, jeśli chciałbyś zakończyć linię bez wymuszania opróżnienia bufora możesz wypisać znak \n

W ten sposób niestety nie skasujesz całej zawartości konsoli, pod systemami Unixopodobynimi (np. Linux) możesz użyć ANSI escape codes, ale niestety na Windowsie nie zadziałają.

Pod Windowsem do skasowania zawartości konsoli możesz użyć FillConsoleOutputCharacter.

Potrzebujesz tylko uchwytu do wyjścia konsoli, uchwyt ten możesz uzyskać funkcją GetStdHandle.

HANDLE uchwyt_konsoli = GetStdHandle(STD_OUTPUT_HANDLE);
COORD lewy_gorny_rog = { 0, 0 };
DWORD zapisane_znaki;
FillConsoleOutputCharacter(uchwyt_konsoli, TEXT(' '), 80 * 300, lewy_gorny_rog, &zapisane_znaki);

HANDLE to typ uchwytu, nie musisz się przejmować co to dokładnie jest, po prostu zmienne takiego typu są uchwytami. Do zmiennej uchwyt_konsoli pobieramy uchwyt do konsoli :wink:

STD_OUTPUT_HANDLE to stała liczbowa, która mówi funkcji GetStdHandle, że chodzi nam o uchwyt do standardowego wyjścia (czyli najczęściej konsoli).

Zmienna lewy_gorny_rog jest typu COORD. COORD to struktura o dwóch polach, które inicjalizujemy zerami, czyli będziemy mieć współrzędne lewego górnego rogu konsoli.

Pola struktury COORD nazywają się odpowiednio X i Y. Zamiast

COORD lewy_gorny_rog = { 0, 0 };

możnaby napisać

COORD lewy_gorny_rog;
lewy_gorny_rog.X = 0;
lewy_gorny_rog.Y = 0;

i wyszłoby na to samo.

DWORD oznacza po prostu 32-bitową liczbę naturalną.

FillConsoleOutputCharacter przyjmuje po kolei:

  • uchwyt do konsoli;

  • znak, którym ma wypełnić obszar, dajemy spację;

  • ilość znaków do wypisania (wpisałem tu na sztywno 80 * 300, bo taki jest zazwyczaj rozmiar bufora konsoli, jednak nie zaleca się wpisywania takich liczb bezpośrednio w miejscu użycia, lepiej byłoby zadeklarować nazwaną stałą o takiej wartości i jej używać (szczególnie wygodne gdy trzeba użyć w kilku miejscach tej samej wartości), natomiast w tak drobnym przykładzie na razie przymknijmy na to oko :wink: (natomiast w większych projektach dużo lepiej używać nazwanych stałych));

  • współrzędne, od których zacznie wypisywać znak, tutaj podajemy zmienną lewy_gorny_rog, którą zadeklarowaliśmy wcześniej;

  • na koniec trzeba podać wskaźnik do zmiennej typu DWORD, w której funkcja zapisze ile znaków udało jej się nadpisać (nawet jeśli nie potrzebujemy tej informacji, to jednak funkcja wymaga podania jej tego wskaźnika). Znak ampersand & oznacza pobranie adresu zmiennej. Funkcji nie interesuje wartość tej zmiennej, tylko gdzie ta zmienna jest, żeby mogła coś do niej zapisać.

Jeszcze wyjaśnienie, dlaczego napisałem TEXT(’ ') zamiast po prostu ’ '.

Otóż w WinAPI prawie każda funkcja przyjmująca tekst, występuje w dwóch wersjach, jedna wersja przyjmuje znaki kodowane aktualnie ustawioną w systemie stroną kodową, a druga przyjmuje tzw. szerokie znaki, czyli znaki kodowane w Unicode.

Jeśli przed dołączeniem nagłówka <Windows.h> zostanie zdefiniowane makro UNICODE, to ta linijka przyjmie następującą postać

FillConsoleOutputCharacterW(uchwyt_konsoli, L' ', 80 * 300, lewy_gorny_rog, &zapisane_znaki);

A jeśli nie będzie makra UNICODE to

FillConsoleOutputCharacterA(uchwyt_konsoli, ' ', 80 * 300, lewy_gorny_rog, &zapisane_znaki);

(zauważ, że teraz nazwa funkcji kończy się na A lub W w zależności od wersji)

Mógłbyś jawnie wpisać którąś z powyższych linii kodu i wtedy miałbyś zawsze używaną tę samą wersję, niezależnie od użycia makra UNICODE.

Literka L przy znaku w apostrofach oznacza, że jest to szeroki znak (WCHAR).

Bez użycia makra TEXT(), gdyby było zdefiniowane makro UNICODE to taka linia

FillConsoleOutputCharacter(uchwyt_konsoli, ' ', 80 * 300, lewy_gorny_rog, &zapisane_znaki);

przekształciłaby się w

FillConsoleOutputCharacterW(uchwyt_konsoli, ' ', 80 * 300, lewy_gorny_rog, &zapisane_znaki);

Co już mogłoby spowodować błąd (akurat przy pojedynczych znakach może nastąpić rzutowanie typów, ale przy ciągach znaków już byś dostał błąd niezgodności typów).

Makro UNICODE możesz zdefiniować samemu

#define UNICODE

lub ustawić w ustawieniach projektu.

Więcej szczegółów możesz doczytać w tym artykule http://web.archive.org/web/20111012012958/http://warsztat.gd/articles.php?x=view&id=270 (jakby nie chciał się załadować to wersja spakowana http://chomikuj.pl/Rolek__/Dokumenty/Unicode+w+Visual+Cpp,4454081681.zip(archive))

Jeszcze zamiast wpisywać na sztywno ile znaków ma być nadpisane, można pobrać rozmiary konsoli i zawsze nadpisywać odpowiednią ilość znaków.

Do pobrania rozmiarów konsoli można użyć funkcji GetConsoleScreenBufferInfo, która wypełni strukturę typu CONSOLE_SCREEN_BUFFER_INFO różnymi informacjami na temat bufora ekranu konsoli. Struktura CONSOLE_SCREE_BUFFER_INFO posiada pole dwSize, które zawiera rozmiary bufora ekranu konsoli, to pole jest typu COORD, czyli ma własne pola X i Y, określające odpowiednio szerokość i wysokość.

CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(uchwyt_konsoli, &csbi);
FillConsoleOutputCharacter(uchwyt_konsoli, TEXT(' '), csbi.dwSize.X * csbi.dwSize.Y, lewy_gorny_rog, &zapisane_znaki);

Na koniec trzeba jeszcze przenieść kursor do lewego górnego rogu, można to zrobić funkcją SetConsoleCursorPosition

COORD lewy_gorny_rog = { 0, 0 };
SetConsoleCursorPosition(uchwyt_konsoli, lewy_gorny_rog);

Ostatecznie cały ten kod możesz wyłączyć sobie do osobnej funkcji , którą będziesz wywoływał gdy będziesz chciał wyczyścić konsolę :slight_smile:

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

using namespace std;

void wyczyscKonsole()
{
	HANDLE uchwyt_konsoli = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	GetConsoleScreenBufferInfo(uchwyt_konsoli, &csbi);
	COORD lewy_gorny_rog = { 0, 0 };
	DWORD zapisane_znaki;
	FillConsoleOutputCharacter(uchwyt_konsoli, TEXT(' '), csbi.dwSize.X * csbi.dwSize.Y, lewy_gorny_rog, &zapisane_znaki);
	SetConsoleCursorPosition(uchwyt_konsoli, lewy_gorny_rog);
}

int main()
{

	for (int i = 15; i >= 0; i--)
	{
		Sleep(1000);
		wyczyscKonsole();
		cout << i << endl;
	}
	cout << "JEBUT Nowy Rok!!!";
	return 0;
}

PS. Jak się uczysz to mogę Ci polecić następujące tutoriale (mają kilka lat, ale nadal uważam, że są dobre):

Oraz kilka dodatkowych rzeczy:

Miłej zabawy :wink: