Skocz do zawartości

Zarchiwizowany

Ten temat jest archiwizowany i nie można dodawać nowych odpowiedzi.

nyac55

C# - Program Kalkulator w obiektowym z Odwróconą Notacją Polska?

Polecane posty

Witam. Obecnie mam do przygotowania projekt w języku C# obiektowym z wykorzystaniem Odwróconej Notacji Polskiej. Program ma zawierać bibliotekę ,w której wszystko ma być załączone oraz interfejs graficzny GUI. Na przykład wciskamy liczbę ,dajemy zatwierdź ,następnie 2 liczbę znowu zatwierdź oraz znak i zatwierdź ,później = i zatwierdź. Profesor proponował użycie stosu w programie itd. Jeszcze nie pisałem żadnej biblioteki ,ani aplikacji obiektowej do tergo dochodzi ONP. Proszę o jakieś porady odnośnie tego jak mógłbym to zrealizować oraz jak napisać bibilotekę DLL.

Link do komentarza
Udostępnij na innych stronach

nyac55 -> C# jest sam w sobie obiektowy. Nie wiem, co by za obiektowe magie można było odprawiać przy prostym kalkulatorze. Chyba jedna klasa z logiką kalkulatora, a druga GUI. Samo GUI najprościej będzie Ci zrobić w Windows Forms (choć WPF też jest łatwy).

DLL robisz dodając drugi projekt do solucji, czyli masz jeden projekt Window Application / WPF Application, a drugi Class Library. Poza tym projekt z GUI ma referencję do projektu Class Library. Stos możesz zorganizować za pomocą klasy Queue(T).

Zdzisiu -> Unity służy do grafiki 2D i 3D, więc nie widzę sensu się w to pakować przy projekcie typu kalkulator.

Link do komentarza
Udostępnij na innych stronach

Z jednej strony masz rację, ale po co łapać kilka srok za ogon? Kolega pisze że dopiero uczy się obiektówki, więc lepiej żeby robił to w formsach (chociaż osobiście polecałbym od razu przejść do WPF ze względu na większą funkcjonalność i bardziej przyszłościowy model customizacji graficznej), które są integralną częścią VS, niż pakować się w jakieś dziwne silniki. Zwlaszcza że Unity jest raczej stosowany do gier, przy programowaniu czysto biznesowym jest średnio przydatny. Nie mówię że nie warto się go uczyć, ale na razie nie jest to potrzebne.

Link do komentarza
Udostępnij na innych stronach

@ wies.niak Unity jest powrzechnie stosowany do pisania gier i aplikacji mobilnych.

Czyli nadaje się idealnie do stworzenia prostego kalkulatora... Każde narzędzie ma swoje zastosowanie i używanie cegły zamiast młotka do wbicia gwoździa nie jest najlepszym pomysłem. Moża, tylko po co?

Link do komentarza
Udostępnij na innych stronach

Teraz do interfejsu graficznego GUI dowiązałem 2 projekt z klasą ,która ma być biblioteką dll.

____________

Przepraszam za pomyłkę ,nie muszę używać stosu. Wystarczy wprowadzanie wartości liczb do zmiennych za pomocą funkcji.

Czy ktoś mógłby podać jakiś przykład jak mogę dane wprowadzone na kalkulatorze przekazać do biblioteki ,w której jest funkcja ,która np. wprowadza tą daną pod zmienną a??

Link do komentarza
Udostępnij na innych stronach

Biblioteka wprowadza podział logiczny kodu, natomiast w żaden sposób nie wpływa na jego użycie (tylko trzeba powiązać projekty za pomocą referencji - pisałem o tym wcześniej). Co za tym idzie, jeśli masz klasę Kalkulator, to tworzysz gdzieś w code-behind interfejsu obiekt klasy Kalkulator, po czym korzystasz z tego obiektu i jego metod.

Link do komentarza
Udostępnij na innych stronach

W takim razie czy ten zapis będzie poprawny:


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 Projekt1_Windows_Forms
{
public partial class Form1 : Form
{
Form1 obiekt = new Form1();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.AppendText("1");
}
// ...

Stworzyłem obiekt klasy Form1. //kod behind programu

Lub tak:


liczba liczba = new liczba();

//klasa w bibliotece dll

Nie wiem, gdzie dokładnie mam stworzyć obiekt, lecz wydaje mi się, że powinienem stworzyć w dll'ce. Aczkolwiek, czy stworzę obiekt w kodzie behind czy dll'ce obiekt nie jest widziany ,gdzie indziej niż miejsce stworzenia.

Link do komentarza
Udostępnij na innych stronach

Kiedy ma następować obliczanie wprowadzonego wyrażenia?

W dll zamieściłbym klasę zawierającą mechanizmy obliczeniowe, powiedzmy "CalculatorCore", a w projekcie głównym okienko kalkulatora, czyli GUI.

Najprościej będzie zrobić obiekt klasy CalculatorCore jako pole klasy okna - będziesz miał dostęp do niej z każdego zdarzenia okna.

Link do komentarza
Udostępnij na innych stronach

Kalkulator ma działać w Odwrotnej Notacji Polskiej, tak więc np. wprowadzamy 1 zmienną w GUI do tekstboxa i jeśli klikniemy zatwierdź, wartość przypisywana jest do zmiennej. To samo z 2 zmienną, natomiast na koniec wprowadzamy znak i jeśli klikniemy zatwierdź chyba powinno liczyć lub ewentualnie po tym jeszcze klikamy = i zatwierdzamy i wtedy liczy.

Poniżej zamieszczam efekty mojej pracy:


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;
using Projekt1_biblioteka_dll;

namespace Projekt1_Windows_Forms
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
textBox1.AppendText("1");
}

private void button2_Click(object sender, EventArgs e)
{
textBox1.AppendText("2");
}

private void button3_Click(object sender, EventArgs e)
{
textBox1.AppendText("3");
}

private void button4_Click(object sender, EventArgs e)
{
textBox1.AppendText("4");
}

private void button5_Click(object sender, EventArgs e)
{
textBox1.AppendText("5");
}

private void button6_Click(object sender, EventArgs e)
{
textBox1.AppendText("6");
}

private void button7_Click(object sender, EventArgs e)
{
textBox1.AppendText("7");
}

private void button8_Click(object sender, EventArgs e)
{
textBox1.AppendText("8");
}

private void button9_Click(object sender, EventArgs e)
{
textBox1.AppendText("9");
}

private void button0_Click(object sender, EventArgs e)
{
textBox1.AppendText("0");
}

private void button19_Click(object sender, EventArgs e)
{
textBox1.AppendText(",");
}

private void button11_Click(object sender, EventArgs e)
{
textBox1.Text = "";
}

private void button12_Click(object sender, EventArgs e)
{
textBox1.AppendText("+");
}

private void button14_Click(object sender, EventArgs e)
{
textBox1.AppendText("-");
}

private void button15_Click(object sender, EventArgs e)
{
textBox1.AppendText("*");
}

private void button16_Click(object sender, EventArgs e)
{
textBox1.AppendText("/");
}

private void Backspace_button_Click(object sender, EventArgs e)
{
int textLength = textBox1.Text.Length;
if (textLength > 0)
textBox1.Text = textBox1.Text.Substring(0, textLength - 1);
}

private void Sign_button_Click(object sender, EventArgs e) // zmiana wartości liczby z textBoxa na ujemną //bądź odwrotnie.
{
int textLength = textBox1.Text.Length;
if (textLength > 0)
if ((textBox1.Text[0]).Equals('-'))
textBox1.Text = textBox1.Text.Substring(1, textLength - 1);
else textBox1.Text = "-" + textBox1.Text;
else textBox1.Text = "-" + textBox1.Text;
}

private void Accept_button_Click(object sender, EventArgs e)
{
double liczba1, liczba2;
char sign;
liczba1 = double.Parse(textBox1.Text);
if (liczba1 == 0)
{
liczba1 = double.Parse(textBox1.Text);
}
else
{
liczba2 = double.Parse(textBox1.Text);
}
}

private void Equal_button_Click(object sender, EventArgs e)
{
switch (sign)
{
case('+'):
textBox1.Text = (liczba + Double.Parse(textBox1.Text)).ToString();
break;
case('-'):
textBox1.Text = (liczba - Double.Parse(textBox1.Text)).ToString();
break;
case('*'):
textBox1.Text = (liczba * Double.Parse(textBox1.Text)).ToString();
break;
case('/'):
if (textBox1.TextLength == 1 && textBox1.Text[0].Equals('0'))
{
textBox1.Text = ("Error! Divide by zero!");
}
else
{
textBox1.Text = ((double)liczba / double.Parse(textBox1.Text)).ToString();
}
break;
}
}
}
}

// kod behind GUI


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Projekt1_biblioteka_dll;
namespace Projekt1_Windows_Forms
{
static class Program
{
/// <summary>
/// Główny punkt wejścia dla aplikacji.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

//program główny


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

namespace Projekt1_biblioteka_dll
{
public class CalculatorCore
{
CalculatorCore liczba = new CalculatorCore();
double liczba1,liczba2;
char znak;
void oblicz()
{

}
}
}

// biblioteka dll

_+_+_+_

Dodam, że efekty spod buttonu '=' są tymczasowe, chciałem sprawdzić jak ma to wyglądać później.

Link do komentarza
Udostępnij na innych stronach

Form1 liczenie new Form1;

liczba liczba = new liczba();

Po co?

Przyciski - mam zgadywać, co robi np button17?

 private void button13_Click(object sender, EventArgs e)
{
int textLength = textBox1.Text.Length;
if (textLength > 0)
if ((textBox1.Text[0]).Equals('-'))
textBox1.Text = textBox1.Text.Substring(1, textLength - 1);
else textBox1.Text = "-" + textBox1.Text;
else textBox1.Text = "-" + textBox1.Text;
}

Używaj nawiasów klamrowych nawet do pojedynczych/krótkich warunków. Powyższy kod jest nieczytelny.

Twoja klasa do liczenia jest pusta - trudno coś tu powiedzieć. Poza tym nazwa "liczba" nie oddaje przeznaczenia.

Link do komentarza
Udostępnij na innych stronach

Zmodyfikowałem nieco program powyżej. Obecnie zastanawiam się jak miałoby to działać myślę, że w GUI program dla Buttona Zatwierdź ->Accept_Button może sprawdzać czy np. nie podaliśmy znaku w textBox'ie i wtedy jeśli znaku nie ma przesyła w jakiś sposób wartość z textBox'a do odpowiedniej funkcji klasy CalkulatorCore biblioteki dll. Problem w tym, że gdy porównuję string z znakiem np. "+" i później piszę || (lub), żeby dalej podać kolejny znak "-" program wyświetla komunikat błędy, że nie można tak robić dla Stringa. Jak mogę to zrobić inaczej? oraz czy moja koncepcja na rozwiązanie problemu jest dobra?

_+_+_+_


private void Accept_button_Click(object sender, EventArgs e)
{
if(textBox1.Text != "+")
{
liczba = (double.Parse(textBox1.Text)).ToString();
}
}

// kod behind


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Threading.Tasks;
namespace Projekt1_biblioteka_dll
{
public class CalculatorCore
{
CalculatorCore liczba = new CalculatorCore();
public double liczba,liczba2;
char znak;
void zmienna()
{

}
}
}
//dll -> jaki powinien być zapis, żeby zmienna liczba była //widoczna (w ddl'ce z kodu behind)?

Link do komentarza
Udostępnij na innych stronach

http://pl.wikipedia.org/wiki/Odwrotna_notacja_polska

Polecam przeczytać "Algorytm obliczenia wartości wyrażenia ONP".

Ja bym zrobił tak, że w klasie CalculatorCore miałbym wewnętrzną listę na kolejne elementy wyrażenia - List<string>.

Stworzyłbym metodę "AddElementToList", za pomocą której ładowałbym kolejne liczby/operatory z gui do wspomnianej listy.

Stworzyłbym metodę "CalculateExpression", która by była wołana po wykryciu znaku równości albo po naciśnięciu jakiegoś przycisku "oblicz". W ramach tej metody robiłbym dokładnie to, co jest opisane w zalinkowanym artykule. Metoda może zwracać wynik obliczeń lub null jeśli podany ciąg był błędny.

Dodatkowo stworzyłbym metodę "GetElementType", która będzie przyjmować pojedynczy element wyrażenia i zwracać jego rodzaj - liczba lub operator (używamy tu wyliczenia - enum). Dla wygody metoda ta może mieć parametry wyjściowe "value" oraz "operator". Za pomocą tych parametrów możemy od razu dostać informację o wartości liczby lub operatora (kolejny enum) przez co nie musimy wykonywać ponownego parsowania.

Potrzebujesz też stosu - na stosie lądują tylko liczby, więc może to być Stack<int> lub Stack<double> - zależy, jakie liczby chcesz obsługiwać.

CalculatorCore liczba = new CalculatorCore();

Takie coś powinieneś mieć w klasie okna, a nie w CalculatorCore.

Link do komentarza
Udostępnij na innych stronach

OK, aczkolwiek mój program nie musi być taki zaawansowany. Dostałem informację ,że wartości nie muszą lądować na stosie tylko 1 wartość jest przypisana do 1 zmiennej ,a 2 wartość do 2, po tym wczytujemy znak i obliczamy. Chciałbym to zrobić jak najszybciej, gdyż jeśli oddam projekt przed świętami (czwartek) program może nie do końca działać oraz nie będę musiał tworzyć instrukcji programisty oraz użytkownika itd. Tak więc muszę się sprężyć ,aczkolwiek z moimi umiejętnościami programowania nie będzie łatwo. Dodałem także tą linijkę do swojego projektu w dll'ce ,aczkolwiek gdy wpisuję liczba w kodzie behind obiekt nie jest widoczny -> oczywiście dodałem przestrzeń nazewniczą w using'ach projektu itd.

_______________

Myślę, że to się da zrobić bez stosu w moim przypadku:


using Projekt1_biblioteka_dll;
// ...
private void button12_Click(object sender, EventArgs e) //button +
{
textBox1.AppendText("+");
//pobierz_znak(); //próbowałem to zrobić za pomocą metody, aczkolwiek ani metoda ,ani stworzony obiekt nie jest widoczny w kodzie behind
pobierz_znak.Add("+"); // to samo z pomocą listy. Do listy dodaję znak
}


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Threading.Tasks;
namespace Projekt1_biblioteka_dll
{
public class CalculatorCore
{
double liczba;
char znak;
CalculatorCore liczba = new CalculatorCore();
List<string> pobierz_znak = new List<string>;
void pobierz_znak()
{
znak = textBox1.Text;
}
}
}

<- To co umieściłem w bibliotece dll

Link do komentarza
Udostępnij na innych stronach

OK, aczkolwiek mój program nie musi być taki zaawansowany. Dostałem informację ,że wartości nie muszą lądować na stosie tylko 1 wartość jest przypisana do 1 zmiennej ,a 2 wartość do 2, po tym wczytujemy znak i obliczamy. Chciałbym to zrobić jak najszybciej, gdyż jeśli oddam projekt przed świętami (czwartek) program może nie do końca działać oraz nie będę musiał tworzyć instrukcji programisty oraz użytkownika itd. Tak więc muszę się sprężyć ,aczkolwiek z moimi umiejętnościami programowania nie będzie łatwo. Dodałem także tą linijkę do swojego projektu w dll'ce ,aczkolwiek gdy wpisuję liczba w kodzie behind obiekt nie jest widoczny -> oczywiście dodałem przestrzeń nazewniczą w using'ach projektu itd.

Absolutnie bez sensu. Klakulator ONP, który realizuje tylko proste wyrażenia typu "A B Operator" to trochę parodia. Do czwartku masz tyle czasu, że 30 razy zdążyłbyś to napisać. No, ale rób jak chcesz - IMO podałem Ci najprostszy sposób realizacji, a obsługa stosu jest dziecinnie prosta. W dll nie możesz referować do projektu GUI. Raz, że to nielogiczne, bo to GUI ma sterować, a nie biblioteka (nie ma tu sytuacji, że GUI oczekuje na jakiś sygnał z niższej warstwy, np nadchodzące połączenie), dwa to nierealizowalne - dostaniesz referencję krzyżową (biblioteka A wymaga B, a B wymaga A).

Link do komentarza
Udostępnij na innych stronach

OK, czyli wszystkie funkcje mam w bibliotece ,natomiast obiekt tworzę w GUI i odwołuję się do funkcji w bibliotece, tak? Obiekt może być w funkcjonalności danego buttona czy w kodzie behind GUI? Czy muszę tworzyć stos czy ta lista będzie pełnić funkcję stosu? W razie ,gdyby mi się nie udało napisać do czwartku ,dałbyś radę pomóc*...

Link do komentarza
Udostępnij na innych stronach

OK, czyli wszystkie funkcje mam w bibliotece ,natomiast obiekt tworzę w GUI i odwołuję się do funkcji w bibliotece, tak?

Tak.

Obiekt może być w funkcjonalności danego buttona czy w kodzie behind GUI?

Zrób go jako pole klasy. Poza tym code-behind to termin określający klasę będącą częścią wygenerowanego GUI. Obsługa zdarzenia przycisku też znajduje się w code-behind.

Czy muszę tworzyć stos czy ta lista będzie pełnić funkcję stosu?

Użyj stosu, skoro jest dedykowana kolekcja.

W razie ,gdyby mi się nie udało napisać do czwartku ,dałbyś radę pomóc*...

Nie zrobię za Ciebie tego zadania.

Link do komentarza
Udostępnij na innych stronach

Tworząc obiekt w kodzie behind GUI, powinno być coś takiego:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Projekt1_biblioteka_dll;
namespace Projekt1_Windows_Forms
{
static public class Program
{
CalculatorCore liczba = new CalculatorCore(); //CalculatorCore mi podkreśla, że nie istnieje w bieżącym kontekście
/// <summary>
/// Główny punkt wejścia dla aplikacji.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

Jeśli chcę się odwołać do danej funkcji przez obiekt stosuję zapis:


liczba.pobierz_znak();

?

Link do komentarza
Udostępnij na innych stronach

Znalazłem takie coś:


abstract class Zwierze
{
public abstract void DajGlos();
}

class Ssaki : Zwierze
{
public override void DajGlos()
{
Console.WriteLine("Ssak wydaje dzwiek!");
}
}

class Ptaki : Zwierze
{
public override void DajGlos()
{
Console.WriteLine("Ptak wydaje dzwiek!");
}
}

class Plazy : Zwierze
{
public override void DajGlos()
{
Console.WriteLine("Plaz wydaje dzwiek!");
}
}

class Pokaz
{
public static void Main()
{
Zwierze[] zwierzak = new Zwierze[3];
zwierzak[0] = new Ssaki();
zwierzak[1] = new Ptaki();
zwierzak[2] = new Plazy();

zwierzak[0].DajGlos();
zwierzak[1].DajGlos();
zwierzak[2].DajGlos();

Console.ReadKey();
}
}

Czy tak jak jest w podanym przykładzie powinienem stworzyć nową klasę, a następnie w niej utworzyć obiekt i wtedy już mogę się odwoływać do metody z klasy głównej?

Link do komentarza
Udostępnij na innych stronach



  • Kto przegląda   0 użytkowników

    • Brak zalogowanych użytkowników przeglądających tę stronę.

×
×
  • Utwórz nowe...